home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 138 / 138.xpi / chrome / stumbleupon.jar / content / datastore.js < prev    next >
Text File  |  2010-01-22  |  72KB  |  2,869 lines

  1. /***
  2.     * Datastore class
  3.     * 
  4.     * handles persistent data and lookup tables
  5.     */
  6. var su_Datastore = function (parent, enabledb)
  7. {
  8.     this._components = Components;
  9.     this._parent = parent;
  10.     this.globals = this._parent._globals;
  11.     
  12.     // The following in-memory hashtables help minimize the data that
  13.     // must be stored persistently.  They could be replaced when we 
  14.     // eventually eliminate prefs tables in favor of db tables.
  15.     //   sls: array of slstats objects that are used to build $slstats;
  16.     //        some stats get updated incrementally when we do sequential
  17.     //        10-url hits to links.php
  18.     // sluqh: hash of url->slq that indicates to the content click 
  19.     //        handler that a page contains tracked links
  20.     // sltih: hash of slt->sli, where slt is a query-specific id of
  21.     //        tracked link targets and where sli is a record of tracking
  22.     //        details
  23.     this.globals.sls = new Array();
  24.     this.globals.sluqh = new Object();
  25.     this.globals.sltih = new Object();
  26.     
  27.     this.prefRetries = 1000;
  28.     
  29.     this._SCRIPTABLE_INPUT_STREAM_C = new Components.Constructor(
  30.                 "@mozilla.org/scriptableinputstream;1",
  31.                 "nsIScriptableInputStream");
  32.  
  33.     this._NSIFILE_PATH_C = new Components.Constructor(
  34.                 "@mozilla.org/file/local;1",
  35.                 "nsILocalFile",
  36.                 "initWithPath");
  37.     
  38.     this._prefAccessInitialized = false;
  39.     this._prefService = null;
  40.     this._prefBranch = null;
  41.     this._initPrefAccess();
  42.     this._prefsDirty = false;
  43.     
  44.     try {
  45.         // When we start using this, we need to initialize similarly to
  46.         // prefs, logging errors and retrying as necessary.  -- JW
  47.         var localeService =
  48.                     Components.classes["@mozilla.org/intl/nslocaleservice;1"]
  49.                     .getService(Components.interfaces.nsILocaleService);
  50.         var stringBundleService =
  51.                     Components.classes["@mozilla.org/intl/stringbundle;1"]
  52.                     .getService(Components.interfaces.nsIStringBundleService);
  53.         this._stringBundle = stringBundleService.createBundle(
  54.                     "chrome://stumbleupon/locale/stumbleupon.properties",
  55.                     localeService.getApplicationLocale());
  56.     } catch (e) {}
  57.     
  58.     this._dicts = new Object();
  59.     this._initConstants();
  60.     this._enabledb = enabledb;
  61.     
  62.     this._userdb = null;
  63.     this._ycc = null;
  64.     
  65.     this._userid = this.getValue("@current_user");
  66.     
  67.     this._installResourceQueue = new Array();
  68.     this._installResourcePendingCount = 0;
  69.     
  70.     this._catnums = null;
  71.     this._foldernames = null;
  72.     this._bmcattags = null;
  73.  
  74.     this._sortedThruChannels = null;
  75.     this._channelsByDomain = null; 
  76.         
  77. //    this._queuedFileWriteSpecs = new Array();
  78.  
  79.     this.eventListenerListsByEventId = new Object();
  80.     
  81.     var mediator = this._getService(
  82.             "@mozilla.org/appshell/window-mediator;1",
  83.             "nsIWindowMediator");
  84.     mediator.addListener(this);
  85. }
  86. su_Datastore.prototype =
  87. { // BEGIN prototype
  88.  
  89. // called by parent upon xpcom shutdown
  90. destroy: function ()
  91. {
  92.     this._parent = null;
  93. },
  94.  
  95. _setUserid: function (newUserid)
  96. {
  97.     if (newUserid == "")
  98.     {
  99.         if (this._enabledb)
  100.             this._closeUserDB();
  101.         this.clearUserSessionGlobals();
  102.         this._userid = newUserid;
  103.     }
  104.     else
  105.     {
  106.         if (this._enabledb)
  107.             this._closeUserDB();
  108.         this.clearUserSessionGlobals();
  109.         this._userid = newUserid;
  110.         if (this._enabledb)
  111.             this._openUserDB();
  112.     }
  113.     this._ycc = null;
  114. },
  115.  
  116. getCC: function ()
  117. {
  118.     if (this._ycc === null)
  119.     {
  120.         if (this._userid == "")
  121.             return "";
  122.         
  123.         this._ycc = encodeURIComponent(this.getPrefValue("$ycc"));
  124.     }
  125.     return this._ycc;
  126. },
  127.  
  128. logEvent: function (event_str)
  129. {
  130.     if (! this._enabledb)
  131.         return;
  132.     try {
  133.         var db = this.getDatabase();
  134.         db.a("INSERT INTO event_log (type,occurred) VALUES (");
  135.         db.as(event_str);
  136.         db.alv(Math.floor((new Date().getTime())/1000));
  137.         db.query();
  138.     } catch (e) {}
  139. },
  140.  
  141. setCC: function (str)
  142. {
  143.     this._ycc = encodeURIComponent(str);
  144.     this.setPrefValue("$ycc", str);
  145. },
  146.  
  147. _openUserDB: function ()
  148. {
  149.     if (! this._userid)
  150.     {
  151.         this._userdb = null;
  152.         return;    
  153.     }
  154.  
  155.     if (this._userid == "")
  156.     {
  157.         this._userdb = null;
  158.         return;
  159.     }
  160.  
  161.     this._userdb = new su_DatabaseConnection(
  162.             this,
  163.             "user" + this._userid);
  164.     
  165.     var dbfile = this._userdb.getDBFile();
  166.     
  167.     if (! dbfile.exists())
  168.     {
  169.         var nsiuri = this._createInstance(
  170.                     "@mozilla.org/network/standard-url;1",
  171.                     "nsIURI");
  172.         nsiuri.spec = "chrome://stumbleupon/content/userdb.sql";
  173.         var sql = this.readURI(nsiuri);
  174.         this._userdb.beginTransaction();
  175.         this._userdb.query("PRAGMA auto_vacuum = 1");
  176.         this._userdb.query(sql);
  177.         this._userdb.commitTransaction();
  178.     }
  179.  
  180.     try {
  181.         this._upgradeProfileDB();
  182.     } catch (e) { this._logError(false, "DB UPGRADE", e); }
  183.     
  184.     try {
  185.         this._userdb.startDummyStatement();
  186.     } catch (e) { this._logError(false, "DB OPEN", e); }
  187. },
  188.  
  189. _closeUserDB: function ()
  190. {
  191.     if (! this._userdb)
  192.         return;
  193.     this._userdb.skipBackup = true;
  194.     this._userdb.stopDummyStatement();
  195.     this._userdb.destroy();
  196.     this._userdb = null;
  197. },
  198.  
  199. getDatabase: function ()
  200. {
  201.     if (this._userdb)
  202.         return this._userdb;
  203.     
  204.     this._openUserDB();
  205.     
  206.     return this._userdb;
  207. },
  208.  
  209. getUrlid: function (url)
  210. {
  211.     var db = this.getDatabase();
  212.     var sql;
  213.     var result;
  214.     var row;
  215.     sql = "SELECT urlid FROM url_map WHERE url=" + db.q(url);
  216.     result = db.query(sql);
  217.     if (row = result.shift())
  218.         return row.urlid;
  219.     else
  220.         return null;
  221. },
  222.  
  223. _initPrefAccess: function ()
  224. {
  225.     try {
  226.         this._prefService =
  227.                     Components.classes["@mozilla.org/preferences-service;1"]
  228.                     .getService(Components.interfaces.nsIPrefService);
  229.     
  230.         this._prefBranch = this._prefService.getBranch("");
  231.         
  232.         this._prefAccessInitialized = true;
  233.     } catch (e) { this._logPrefError("PREFS INIT", e); }
  234. },
  235.  
  236. _createInstance: function (nsclass, nsinterface)
  237. {
  238.     try {
  239.         return this._components.classes[nsclass]
  240.                     .createInstance(this._components.interfaces[nsinterface]);
  241.     } catch (e) {
  242.         return null;
  243.     }
  244. },
  245.  
  246. _getService: function (nsclass, nsinterface)
  247. {
  248.     try {
  249.         return this._components.classes[nsclass]
  250.                     .getService(this._components.interfaces[nsinterface]);
  251.     } catch (e) {
  252.         return null;
  253.     }
  254. },
  255.  
  256. // creates an object from a json string
  257. deserialize: function (str)
  258. {
  259.     // This method is derived from the json.org implementation:
  260.     // http://www.json.org/js.html
  261.     // -- JW
  262.  
  263.     try {
  264.         if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
  265.                     test(str))
  266.             return eval('(' + str + ')');
  267.     } catch (e) {}
  268.     return null;
  269. },
  270.  
  271. // creates a json string from an object
  272. serialize: function (obj, include_linefeeds)
  273. {
  274. //    su_dump_object(obj);
  275.     
  276.     return this._JSONRecurse(obj, include_linefeeds).join('');
  277. },
  278.  
  279. _JSONRecurse: function (arg, lf, out)
  280. {
  281.     // [IP:] [kudos:] This method is derived from the TrimPath
  282.     // implementation:
  283.     // http://trimpath.com/project/wiki/JsonLibrary
  284.     // -- JW
  285. /*
  286. Copyright (c) 2002 JSON.org
  287.  
  288. Permission is hereby granted, free of charge, to any person obtaining a copy 
  289. of this software and associated documentation files (the "Software"), to deal 
  290. in the Software without restriction, including without limitation the rights 
  291. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  292. copies of the Software, and to permit persons to whom the Software is 
  293. furnished to do so, subject to the following conditions:
  294.  
  295. The above copyright notice and this permission notice shall be included in all 
  296. copies or substantial portions of the Software.
  297.  
  298. The Software shall be used for Good, not Evil.
  299.  
  300. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  301. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  302. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  303. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  304. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  305. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  306. SOFTWARE.
  307. */
  308.     out = out || new Array();
  309.     var u; // undefined
  310.     
  311.     switch (typeof arg) {
  312.         case 'object':
  313.             if (! arg)
  314.             {
  315.                 out.push('"');
  316.             }
  317.             else if (arg.constructor == Array)
  318.             {
  319.                 out.push('[');
  320.                 var i;
  321.                 for (i = 0; i < arg.length; ++i)
  322.                 {
  323.                     if (i > 0)
  324.                     {
  325.                         if (lf)
  326.                             out.push(',\n');
  327.                         else
  328.                             out.push(',');
  329.                     }
  330.                     try {
  331.                         this._JSONRecurse(arg[i], lf, out);
  332.                     } catch (e) { this._logError(false, "JSON RECURSE_1", e); }
  333.                 }
  334.                 out.push(']');
  335.             }
  336.             else if (typeof arg.toString != 'undefined')
  337.             {
  338.                 out.push('{');
  339.                 var first = true;
  340.                 var p;
  341.                 for (p in arg)
  342.                 {
  343.                     if ((typeof (arg[p])) == "function")
  344.                         continue;
  345.                     var curr = out.length; // Record position to allow undo when arg[p] is undefined.
  346.                     if (! first)
  347.                         if (lf)
  348.                             out.push(',\n');
  349.                         else
  350.                             out.push(',');
  351.                     try {
  352.                         this._JSONRecurse(p, lf, out);
  353.                     } catch (e) { this._logError(false, "JSON RECURSE_2", e); }
  354.                     out.push(':');
  355.                     try {
  356.                         this._JSONRecurse(arg[p], lf, out);
  357.                     } catch (e) { this._logError(false, "JSON RECURSE_3", e); }
  358.                     if (out[out.length - 1] == u)
  359.                         out.splice(curr, out.length - curr);
  360.                     else
  361.                         first = false;
  362.                 }
  363.                 out.push('}');
  364.             }
  365.             break;
  366.         case 'unknown':
  367.         case 'undefined':
  368.         case 'function':
  369.             out.push(u);
  370.             break;
  371.         case 'string':
  372.             out.push('"');
  373.             out.push(arg.replace(/(["\\])/g, '\\$1').replace(/\r/g, '').replace(/\n/g, '\\n'));
  374.             out.push('"');
  375.             break;
  376.         default:
  377.             out.push(String(arg));
  378.             break;
  379.     }
  380.     return out;
  381. },
  382.  
  383. getTimestampStr: function (optFormatMode)
  384. {
  385.     var formatMode = (optFormatMode) ? optFormatMode : 0;
  386.     var now = new Date();
  387.     var monthname=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
  388.     var str = "";
  389.     if (formatMode == 0) // 2008-04-26 12:54:12
  390.     {
  391.         str += now.getFullYear();
  392.         var mtmp = "" + (now.getMonth() + 1);
  393.         if (mtmp.length == 1)
  394.             mtmp = "0" + mtmp;
  395.         str += "-" + mtmp;
  396.         var dtmp = "" + now.getDate();
  397.         if (dtmp.length == 1)
  398.             dtmp = "0" + dtmp;
  399.         str += "-" + dtmp;
  400.         var htmp = "" + now.getHours();
  401.         if (htmp.length == 1)
  402.             htmp = "0" + htmp;
  403.         str += " " + htmp;
  404.         var mintmp = "" + now.getMinutes();
  405.         if (mintmp.length == 1)
  406.             mintmp = "0" + mintmp;
  407.         str += ":" + mintmp;
  408.         var sectmp = "" + now.getSeconds();
  409.         if (sectmp.length == 1)
  410.             sectmp = "0" + sectmp;
  411.         str += ":" + sectmp;
  412.     }
  413.     else if (formatMode == 1) // 12:54pm, Mar 26/08
  414.     {
  415.         var hours = now.getHours();
  416.         var ampm = "am";
  417.         if (hours > 12)
  418.         {
  419.             hours -= 12;
  420.             ampm = "pm";
  421.         }
  422.         str += hours;
  423.         var mintmp = "" + now.getMinutes();
  424.         if (mintmp.length == 1)
  425.             mintmp = "0" + mintmp;
  426.         str += ":" + mintmp;
  427. //        var sectmp = "" + now.getSeconds();
  428. //        if (sectmp.length == 1)
  429. //            sectmp = "0" + sectmp;
  430. //        str += ":" + sectmp;
  431.         str += ampm;
  432.         str += ", " + monthname[now.getMonth()];
  433.         var dtmp = "" + now.getDate();
  434.         if (dtmp.length == 1)
  435.             dtmp = "0" + dtmp;
  436.         str += " " + dtmp;
  437.         var ytmp = "" + now.getFullYear();
  438.         ytmp = ytmp.substr(2, 2);
  439.         str += "/" + ytmp;
  440.     }
  441.     return str;
  442. },
  443.  
  444. _validateFilepathComponent: function (str)
  445. {
  446.     // Disallow characters that have potential to be abused in the case
  447.     // of dns poisoning. -- JW
  448.     var strtmp = str.replace(/[\\\/%\$]/g, "");
  449.     var strtmp = strtmp.replace("..", ".");
  450.     return (str == strtmp);
  451. },
  452.  
  453. _expandKey: function (key)
  454. {
  455.     if (key.charAt(0) == "$")
  456.         return "stumble." + this._userid + "." + key.substr(1);
  457.     else if (key.charAt(0) == "@")
  458.         return "stumble." + key.substr(1);
  459.     else
  460.         return key;
  461. },
  462.  
  463. _getPrefTypeFromValue: function (val)
  464. {
  465.     var type;
  466.     switch (typeof val)
  467.     {
  468.         case "string":  type = "Char"; break;
  469.         case "boolean": type = "Bool"; break;
  470.         case "number":  type = "Int";  break;
  471.         case "object":  type = "JSON"; break;
  472.         default:        type = null;   break;
  473.     }
  474.     return type;
  475. },
  476.  
  477. _verifyPrefAccess: function ()
  478. {
  479.     if (this._prefAccessInitialized)
  480.         return;
  481.     
  482.     this._initPrefAccess();
  483. },
  484.  
  485. getGlobalValue: function (id, optionalOverrideDefault)
  486. {
  487.     if (typeof(this.globals[id.substr(1)]) == "undefined")
  488.     {
  489.         if (typeof(optionalOverrideDefault) == "undefined")
  490.             return this.getDefaultValue(id);
  491.         else
  492.             return optionalOverrideDefault;
  493.     }
  494.     else
  495.     {
  496.         return this.globals[id.substr(1)];
  497.     }
  498. },
  499.  
  500. // Use getValue unless you need to override the default.
  501. getPrefValue: function (id, optionalOverrideDefault)
  502. {
  503.     var type;
  504.     if ((typeof optionalOverrideDefault) == "undefined")
  505.         type = this.getPrefType(id);
  506.     else
  507.         type = this._getPrefTypeFromValue(optionalOverrideDefault);
  508.     
  509.     var jsonFlag = false;
  510.     if (type == "JSON")
  511.     {
  512.         jsonFlag = true;
  513.         type = "Char";
  514.     }
  515.     else if (type == null)
  516.     {
  517.         var e = new Object();
  518.         e.message = "getPrefValue : key [" + id + "] is not defined";
  519.         e.fileName = "chrome://stumbleupon/content/datastore.js";
  520.         e.toString = function (){ return e.fileName + " " + e.message; }
  521.         throw(e);
  522.     }
  523.     
  524.     var value;
  525.     if (this.isPrefDefined(id))
  526.     {
  527.         // get
  528.         var key = this._expandKey(id);
  529.         
  530.         var attemptCount = 0;
  531.         var success = false;
  532.         var error = new Object();
  533.         while ((! success) && (attemptCount < this.prefRetries))
  534.         {
  535.             attemptCount++;
  536.             
  537.             this._verifyPrefAccess();
  538.         
  539.             try {
  540.                 eval("value = this._prefBranch.get" + type + "Pref(key)");
  541.                 success = true;
  542.             }
  543.             catch (e) {
  544. //                error = e;
  545.             }
  546.         }
  547.         
  548.         if (success)
  549.         {
  550.             if (jsonFlag)
  551.                 value = this.deserialize(value);
  552.         }
  553.         else
  554.         {
  555. //            this._logError(true, "PREFS GET", error, id);
  556.             if ((typeof optionalOverrideDefault) == "undefined")
  557.                 value = this.getDefaultValue(id);
  558.             else
  559.                 value = optionalOverrideDefault;
  560.         }
  561.     }
  562.     else
  563.     {
  564.         // get or set
  565.         if ((typeof optionalOverrideDefault) == "undefined")
  566.             value = this.getDefaultValue(id);
  567.         else
  568.             value = optionalOverrideDefault;
  569.         
  570.         this.setValue(id, value);
  571.     }
  572.     
  573.     return value;
  574. },
  575.  
  576. getUserPrefValue: function (tmpUserid, id)
  577. {
  578.     if (id.charAt(0) != "$")
  579.         return null;
  580.     var retval;
  581.     var savedUserid = this._userid;
  582.     this._userid = tmpUserid;
  583.     retval = this.getPrefValue(id);
  584.     this._userid = savedUserid;
  585.     return retval;
  586. },
  587.  
  588. getPrefType: function (id)
  589. {
  590.     if ((id.charAt(0) == "$") || (id.charAt(0) == "@"))
  591.     {
  592.         if ((typeof this._DEFAULTS_BY_ID[id]) != "undefined")
  593.             return this._getPrefTypeFromValue(this._DEFAULTS_BY_ID[id]);
  594.         else
  595.             return null;
  596.     }
  597.     else
  598.     {
  599.         var attemptCount = 0;
  600.         var success = false;
  601.         var error = new Object();
  602.         var type = null;
  603.         while ((! success) && (attemptCount < this.prefRetries))
  604.         {
  605.             attemptCount++;
  606.             
  607.             this._verifyPrefAccess();
  608.         
  609.             try {
  610.                 type = this._prefBranch.getPrefType(id)
  611.                 success = true;
  612.             }
  613.             catch (e) {
  614.                 error = e;
  615.             }
  616.         }
  617.         
  618.         if (success)
  619.         {
  620.             switch (type)
  621.             {
  622.                 case this._prefBranch.PREF_STRING: return "Char";
  623.                 case this._prefBranch.PREF_INT:    return "Int";
  624.                 case this._prefBranch.PREF_BOOL:   return "Bool";
  625.                 default:                           return null;
  626.             }
  627.         }
  628.         else
  629.         {
  630.             this._logError(true, "PREF TYPE", error, id)
  631.             return null;
  632.         }
  633.     }
  634. },
  635.  
  636. // Use this to get preference and locale values.  The first character 
  637. // of param id has the following special meanings:
  638. // $           => current user pref       (ex: "$nick")
  639. // @           => client pref             (ex: "@current_user")
  640. // ~           => browser session global  (ex: "~checked_dyn_channels")
  641. // #           => user session global     (ex: "#installing_all_avatars")
  642. // %           => locale string           (ex: "%menu.anytopic")
  643. // [otherwise] => arbitrary preference
  644. getValue: function (id)
  645. {
  646.     if ((id.charAt(0) == "$") || (id.charAt(0) == "@"))
  647.         return this.getPrefValue(id);
  648.  
  649.     else if ((id.charAt(0) == "#") || (id.charAt(0) == "~"))
  650.         return this.getGlobalValue(id);
  651.  
  652.     else if (id.charAt(0) == "%")
  653.         return this._stringBundle.GetStringFromName(id.substr(1));
  654.     
  655.     else
  656.         return this.getPrefValue(id);
  657. },
  658.  
  659. // Primarily used to retrieve timestamps that are stored as Char to
  660. // avoid overflow.
  661. getIntValue: function (id)
  662. {
  663.     return parseInt(this.getValue(id));
  664. },
  665.  
  666. incrementValue: function (id)
  667. {
  668.     var val = this.getValue(id);
  669.     val++;
  670.     this.setValue(id, val);
  671.     return val;
  672. },
  673.  
  674. getBookmarksService: function ()
  675. {
  676.     return this._getService(
  677.             "@mozilla.org/browser/nav-bookmarks-service;1",
  678.             "nsINavBookmarksService");
  679. },
  680.  
  681. getHistoryService: function (optnsi)
  682. {
  683.     var nsi;
  684.     if (optnsi)
  685.         nsi = optnsi;
  686.     else
  687.         nsi = "nsINavHistoryService";
  688.     var el = this._getService(
  689.             "@mozilla.org/browser/nav-history-service;1",
  690.             nsi);
  691.     return el;
  692. },
  693.  
  694. getTaggingService: function ()
  695. {
  696.     return this._getService(
  697.             "@mozilla.org/browser/tagging-service;1",
  698.             "nsITaggingService");
  699. },
  700.  
  701. /*
  702. getRating: function ()
  703. {
  704.     if (su_host.places)
  705.     {
  706.         var db = su_ds.getDatabase();
  707.         
  708.         db.a("SELECT rating FROM url_map JOIN url ON url_map.urlid=url.urlid WHERE url=" + db.q(url));
  709.         var result = db.query();
  710.         
  711.         if (result.length)
  712.             return result[0].rating;
  713.         else
  714.             return null;
  715.     }
  716.     else
  717.     {
  718.         if (! this._legacyRatingByURL)
  719.             this._loadLegacyRatings();
  720.         
  721.         if ((typeof this._legacyRatingByURL[url]) == "undefined")
  722.             return -1;
  723.         else
  724.             return this._legacyRatingByURL[url];
  725.     }
  726. },
  727.  
  728. getLegacyRatings: function ()
  729. {
  730.     if (! this._legacyRatingByURL)
  731.         this._loadLegacyRatings();
  732.     
  733.     return this._legacyRatingByURL;
  734. },
  735.  
  736. _loadLegacyRatings: function ()
  737. {
  738.     this._legacyRatingByURL = new Object();
  739.     // load ratings
  740.     var file = this.getLegacyNSIFile("stumblerating");
  741.     var str = this.readFile(file);
  742.     var lines = str.split("\n");
  743.     for (var i = 0; i < lines.length; i++)
  744.     {
  745.         if (lines[i] == "")
  746.             continue;
  747.         var parts = lines[i].split(" ");
  748.         this._legacyRatingByURL[parts[0]] = parts[1];
  749.     }
  750. },
  751.  
  752. getLegacyNSIFile: function (type, optOverrideUserid)
  753. {
  754.     var file = this._getService(
  755.                 "@mozilla.org/file/directory_service;1",
  756.                 "nsIProperties")
  757.                 .get("ProfD", Components.interfaces.nsIFile);
  758.     var filename;
  759.     if (optOverrideUserid)
  760.         filename = id + optOverrideUserid;
  761.     else
  762.         filename = id + this._userid;
  763.     
  764.     if (! this._validateFilepathComponent(filename))
  765.         return null;
  766.     
  767.     file.append(filename);
  768.     return file;
  769. },
  770. */
  771.  
  772. clearUserSessionGlobals: function ()
  773. {
  774.     var default_val;
  775.     var id;
  776.     
  777.     for (id in this._DEFAULTS_BY_ID)
  778.     {
  779.         if ((typeof id) != "string")
  780.             continue;
  781.         
  782.         if (id.charAt(0) != "#")
  783.             continue;
  784.         
  785.         default_val = this._DEFAULTS_BY_ID[id];
  786.         
  787.         if (((typeof default_val) == "object") && (default_val != null))
  788.             continue;
  789.         
  790.         this.globals[id.substr(1)] = default_val;
  791.     }
  792.     
  793.     this.clearDictionary("url:url_detail");
  794.  
  795.     this.globals.sls = new Array();
  796.     this.globals.sluqh = new Object();
  797.     this.globals.sltih = new Object();
  798.     this.globals.recent_info_spec = new Object();
  799. },
  800.  
  801. setPrefValueForAllUsers: function (name, value)
  802. {
  803.     var ids = this.getValue("@id_list").split(":");
  804.     var i;
  805.     for (i = 0; i < ids.length; i++)
  806.     {
  807.         if (ids[i] == "")
  808.             continue;
  809.         
  810.         this.setValue("stumble." + ids[i] + "." + name, value);
  811.     }
  812. },
  813.  
  814. selectAllRows: function (tableName)
  815. {
  816.     var tableId = this._TABLE_IDS_BY_NAME[tableName];
  817.     var names = this.getPrefNames("stumble." + this._userid + "." + 
  818.                 tableId + ".");
  819.     
  820.     if (! names)
  821.         return new Array();
  822.     
  823.     var keyFlags = new Object();
  824.     var rows = new Array();
  825.     var row;
  826.     var i;
  827.     for (i = 0; i < names.length; i++)
  828.     {
  829.         var row_str = this.getPrefValue(names[i], "");
  830.         if (row_str == "")
  831.             continue;
  832.         row = this.deserialize(row_str);
  833.         try {
  834.             row._t = tableId; // fixes a migration problem for alpha testers
  835.             
  836.             if (tableId == "d")
  837.             {
  838.                 if (keyFlags[row.domain])
  839.                 {
  840.                     this.deleteRow(row);
  841.                     continue;
  842.                 }
  843.                 keyFlags[row.domain] = 1;
  844.             }
  845.             rows.push(row);
  846.         } catch (e) {}
  847.     }
  848.     return rows;
  849. },
  850.  
  851. insertRow: function (tableName, spec)
  852. {
  853.     spec._t = this._TABLE_IDS_BY_NAME[tableName];
  854.     if (spec._t == "d")
  855.     {
  856.         // do 'REPLACE INTO'
  857.         if (this._channelsByDomain && this._channelsByDomain[spec.domain])
  858.         {
  859.             spec._r = this._channelsByDomain[spec.domain]._r;
  860.             this.updateRow(spec);
  861.             return spec._r;
  862.         }
  863.         
  864.         if (! this._channelsByDomain)
  865.             this._channelsByDomain = new Object();
  866.         
  867.         this._channelsByDomain[spec.domain] = spec;
  868.         
  869.         this._sortedThruChannels = null;
  870.     }
  871.     var autoincName = "stumble." + this._userid + "." + spec._t + "_ai";
  872.     spec._r = this.getPrefValue(autoincName, 0);
  873.     this.setValue(autoincName, (spec._r + 1));
  874.     var name = "stumble." + this._userid + "." + spec._t + "." + spec._r;
  875.     this.setValue(name, this.serialize(spec));
  876.     return spec._r;
  877. },
  878.  
  879. deleteAllRows: function (tableName)
  880. {
  881.     var tableId = this._TABLE_IDS_BY_NAME[tableName];
  882.     var names = this.getPrefNames("stumble." + this._userid + "." + 
  883.                 tableId + ".");
  884.     
  885.     if (! names)
  886.         return;
  887.     
  888.     if (tableId == "d")
  889.     {
  890.         this._sortedThruChannels = null;
  891.         this._channelsByDomain = null;
  892.     }
  893.     
  894.     var i;
  895.     for (i = 0; i < names.length; i++)
  896.         this.clearPref(names[i]);
  897. },
  898.  
  899. selectRow: function (tableName, colName, value, optColName, optValue)
  900. {
  901.     var tableId = this._TABLE_IDS_BY_NAME[tableName];
  902.     var names;
  903.     if (colName == "_r")
  904.     {
  905.         var row_str = this.getPrefValue("stumble." + this._userid + 
  906.                     "." + tableId + "." + value, "");
  907.         if (row_str == "")
  908.             return null;
  909.         else
  910.             return this.deserialize(row_str);
  911.     }
  912.     else if ((tableId == "d") && (colName == "domain"))
  913.     {
  914.         return this.getThruDomainChannel(value);
  915.     }
  916.     else
  917.     {
  918.         names = this.getPrefNames("stumble." + this._userid + "." + 
  919.                 tableId + ".");
  920.     }
  921.     
  922.     if (! names)
  923.         return null;
  924.     
  925.     var row;
  926.     var i;
  927.     if (optColName)
  928.     {
  929.         for (i = 0; i < names.length; i++)
  930.         {
  931.             var row_str = this.getPrefValue(names[i], "");
  932.             if (row_str == "")
  933.                 continue;
  934.             row = this.deserialize(row_str);
  935.             if (((typeof row[colName]) != "undefined")
  936.                     && (row[colName] == value)
  937.                     && ((typeof row[optColName]) != "undefined")
  938.                     && (row[optColName] == optValue))
  939.                 return row;
  940.         }
  941.     }
  942.     else
  943.     {
  944.         for (i = 0; i < names.length; i++)
  945.         {
  946.             var row_str = this.getPrefValue(names[i], "");
  947.             if (row_str == "")
  948.                 continue;
  949.             row = this.deserialize(row_str);
  950.             row._t = tableId; // fixes a migration problem for alpha testers
  951.             if (((typeof row[colName]) != "undefined") && (row[colName] == value))
  952.                 return row;
  953.         }
  954.     }
  955.     return null;
  956. },
  957.  
  958. updateRow: function (spec)
  959. {
  960.     if (spec._t == "d")
  961.         this._sortedThruChannels = null;
  962.     var name = "stumble." + this._userid + "." + spec._t + "." + spec._r;
  963.     this.setValue(name, this.serialize(spec));
  964. },
  965.  
  966. deleteRow: function (spec)
  967. {
  968.     if (spec._t == "d")
  969.     {
  970.         this._sortedThruChannels = null;
  971.         if (this._channelsByDomain && this._channelsByDomain[spec.domain])
  972.             delete this._channelsByDomain[spec.domain];
  973.     }
  974.     var name = "stumble." + this._userid + "." + spec._t + "." + spec._r;
  975.     this.clearPref(name);
  976. },
  977.  
  978. define: function (dictName, key, value)
  979. {
  980.     if ((typeof (this._dicts[dictName])) == "undefined")
  981.         this._dicts[dictName] = new Object();
  982.     this._dicts[dictName][key] = value;
  983. },
  984.  
  985. lookup: function (dictName, key)
  986. {
  987.     var retval = null;
  988.     if (this._dicts[dictName] && 
  989.                 ((typeof (this._dicts[dictName][key])) != "undefined"))
  990.         retval = this._dicts[dictName][key];
  991.  
  992.     return retval;
  993. },
  994.  
  995. undefine: function (dictName, key)
  996. {
  997.     var retval = null;
  998.     if (this._dicts[dictName] && 
  999.                 ((typeof (this._dicts[dictName][key])) != "undefined"))
  1000.     {
  1001.         retval = this._dicts[dictName][key]; 
  1002.         delete this._dicts[dictName][key];
  1003.     }
  1004.  
  1005.     return retval;
  1006. },
  1007.  
  1008. clearDictionary: function (dictName)
  1009. {
  1010.     if ((typeof this._dicts[dictName]) == "object")
  1011.         delete this._dicts[dictName];
  1012. },
  1013.  
  1014. getDictionary: function (dictName)
  1015. {
  1016.     var out;
  1017.     if ((typeof (this._dicts[dictName])) == "object")
  1018.     {
  1019.         out = this._dicts[dictName];
  1020.     }
  1021.     else if ((typeof (this._dicts[dictName])) == "undefined")
  1022.     {
  1023.         this._dicts[dictName] = new Object();
  1024.         out = this._dicts[dictName];
  1025.     }
  1026.     else if (dictName == "catid:topic_name")
  1027.     {
  1028.         this._loadTopicTree();
  1029.         out = this._dicts[dictName];
  1030.     }
  1031.     else if (dictName == "topic_name:catid")
  1032.     {
  1033.         this._loadTopicTree();
  1034.         out = this._dicts[dictName];
  1035.     }
  1036.     else if (dictName == "catid:folder_name")
  1037.     {
  1038.         this._loadTopicTree();
  1039.         out = this._dicts[dictName];
  1040.     }
  1041.     return out;
  1042. },
  1043.             
  1044. setValue: function (id, value)
  1045. {
  1046.     if ((id.charAt(0) == "#") || (id.charAt(0) == "~"))
  1047.         this.globals[id.substr(1)] = value;
  1048.  
  1049.     else
  1050.         this.setPrefValue(id, value);
  1051. },
  1052.  
  1053. setPrefValue: function (id, value)
  1054. {
  1055.     this._prefsDirty = true;
  1056.     
  1057.     var type = this.getPrefType(id);
  1058.     
  1059.     if (type == null)
  1060.     {
  1061. //        if (id != "privacy.popups.disable_from_plugins")
  1062. //            this._logError(false, "UNDECLARED PREF SET WARNING", new Object(), id, value);
  1063.         type = this._getPrefTypeFromValue(value);
  1064.     }
  1065.  
  1066.     if (type == "JSON")
  1067.     {
  1068.         value = this.serialize(value, false);
  1069.         type = "Char";
  1070.     }
  1071.     
  1072.     var key = this._expandKey(id);
  1073.     if (key == "stumble.current_user")
  1074.         this._setUserid(value);
  1075.     
  1076.     var attemptCount = 0;
  1077.     var success = false;
  1078.     var error = new Object();
  1079.     while ((! success) && (attemptCount < this.prefRetries))
  1080.     {
  1081.         attemptCount++;
  1082.         
  1083.         this._verifyPrefAccess();
  1084.     
  1085.         try {
  1086.             eval("this._prefBranch.set" + type + "Pref(key, value)");
  1087.             success = true;
  1088.         }
  1089.         catch (e) {
  1090.             error = e;
  1091.         }
  1092.     }
  1093.     
  1094.     if (! success)
  1095.         this._logError(true, "PREF SET", error, id);
  1096. },
  1097.  
  1098. getDefaultValue: function (id)
  1099. {
  1100.     if ((typeof this._DEFAULTS_BY_ID[id]) != "undefined")
  1101.         return this._DEFAULTS_BY_ID[id];
  1102.     else
  1103.         throw("stumbleupon: Datastore: cannot get default for key [" + id + "]");
  1104. },
  1105.  
  1106. isPrefDefined: function (id)
  1107. {
  1108.     var key = this._expandKey(id);
  1109.     
  1110.     var attemptCount = 0;
  1111.     var success = false;
  1112.     var error = new Object();
  1113.     var defined = null;
  1114.     while ((! success) && (attemptCount < this.prefRetries))
  1115.     {
  1116.         attemptCount++;
  1117.         
  1118.         this._verifyPrefAccess();
  1119.     
  1120.         try {
  1121.             defined = (this._prefBranch.getPrefType(key) != 0);
  1122.             success = true;
  1123.         }
  1124.         catch (e) {
  1125.             error = e;
  1126.         }
  1127.     }
  1128.     if (success)
  1129.     {
  1130.         return defined;
  1131.     }
  1132.     else
  1133.     {
  1134.         this._logError(true, "PREF DEFINED", error, id);
  1135.         return true;
  1136.     }
  1137. },
  1138.  
  1139. clearPref: function (id)
  1140. {
  1141.     var key = this._expandKey(id);
  1142.  
  1143.     if (! this.isPrefDefined(id))
  1144.         return;
  1145.     
  1146.     this._prefsDirty = true;
  1147.     
  1148.     var attemptCount = 0;
  1149.     while ((attemptCount < this.prefRetries))
  1150.     {
  1151.         attemptCount++;
  1152.         
  1153.         this._verifyPrefAccess();
  1154.     
  1155.         try {
  1156.             this._prefBranch.clearUserPref(key);
  1157.         } catch (e) {}
  1158.     }
  1159. },
  1160.  
  1161. getPrefNames: function (prefix)
  1162. {
  1163.     var attemptCount = 0;
  1164.     var success = false;
  1165.     var error = new Object();
  1166.     var list = new Array();
  1167.     while ((! success) && (attemptCount < this.prefRetries))
  1168.     {
  1169.         attemptCount++;
  1170.         
  1171.         this._verifyPrefAccess();
  1172.     
  1173.         try {
  1174.             list = this._prefBranch.getChildList(prefix, {});
  1175.             success = true;
  1176.         }
  1177.         catch (e) {
  1178.             error = e;
  1179.         }
  1180.     }
  1181.     if (! success)
  1182.     {
  1183.         list = new Array();
  1184.         this._logError(true, "PREF NAMES", error, prefix);
  1185.     }
  1186.     return list;
  1187. },
  1188.  
  1189. flushPrefs: function (force)
  1190. {
  1191.     if ((! force) && (! this._prefsDirty))
  1192.         return;
  1193.     this._prefsDirty = false;
  1194.     var attemptCount = 0;
  1195.     var success = false;
  1196.     var error = new Object();
  1197.     while ((! success) && (attemptCount < 1000))
  1198.     {
  1199.         attemptCount++;
  1200.         
  1201.         this._verifyPrefAccess();
  1202.     
  1203.         try {
  1204.             this._prefService.savePrefFile(null);
  1205.             success = true;
  1206.         }
  1207.         catch (e) {
  1208.             error = e;
  1209.         }
  1210.     }
  1211.     if (! success)
  1212.         this._logError(true, "PREF WRITE", error);
  1213. },
  1214.  
  1215. // ioflags
  1216. // RDONLY       0x01
  1217. // WRONLY       0x02
  1218. // RDWR         0x04
  1219. // CREATE_FILE  0x08
  1220. // APPEND       0x10
  1221. // TRUNCATE     0x20
  1222. // SYNC         0x40
  1223. // EXCL         0x80
  1224.  
  1225. readFile: function (nsifile)
  1226. {
  1227.     if (! nsifile.exists())
  1228.         return "";
  1229.     
  1230.     var data = "";
  1231.     
  1232.     try {
  1233.         var nsiuri = this._getService(
  1234.                     "@mozilla.org/network/io-service;1",
  1235.                     "nsIIOService")
  1236.                     .newFileURI(nsifile);
  1237.         data = this.readURI(nsiuri);
  1238.     }
  1239.     catch (e) {
  1240.         if (((typeof nsifile.path) == "string") && 
  1241.                     (nsifile.path.toLowerCase().indexOf("network") != -1))
  1242.             this._logError(false, "READ FILE", e, "network");
  1243.         else
  1244.             this._logError(false, "READ FILE", e, "local");
  1245.         return "";
  1246.     }
  1247.     return data;
  1248. },
  1249.  
  1250. readURI: function (nsiuri)
  1251. {
  1252.     var data = "";
  1253.     
  1254.     var channel = this._getService(
  1255.                 "@mozilla.org/network/io-service;1",
  1256.                 "nsIIOService")
  1257.                 .newChannelFromURI(nsiuri);
  1258.     var input = channel.open();
  1259.     var stream = this._getService(
  1260.                 "@mozilla.org/scriptableinputstream;1",
  1261.                 "nsIScriptableInputStream");
  1262.     stream.init(input);
  1263.     var str_raw = stream.read(input.available());
  1264.     stream.close();
  1265.     input.close();
  1266.     
  1267.     try {
  1268.         var converter = this._createInstance(
  1269.                     "@mozilla.org/intl/scriptableunicodeconverter",
  1270.                     "nsIScriptableUnicodeConverter");
  1271.         converter.charset = "UTF-8";
  1272.         data = converter.ConvertToUnicode(str_raw);
  1273.     }
  1274.     catch( e ) {
  1275.         data = str_raw;
  1276.     }
  1277.     return data;
  1278. },
  1279.  
  1280. writeFile: function (nsifile, str, optAppendFlag)
  1281. {
  1282.     var fstream = null;
  1283.     var channel = null;
  1284.     var attemptCount = 0
  1285.     while ((attemptCount < this.prefRetries) && (! fstream))
  1286.     {
  1287.         attemptCount++;
  1288.         try {
  1289.             var ioservice = this._createInstance(
  1290.                         "@mozilla.org/network/io-service;1",
  1291.                         "nsIIOService");
  1292.             channel = ioservice.newChannelFromURI(
  1293.                         ioservice.newFileURI(nsifile));
  1294.             fstream = this._createInstance(
  1295.                         "@mozilla.org/network/file-output-stream;1",
  1296.                         "nsIFileOutputStream");
  1297.         } catch (e) {}
  1298.     }
  1299.     
  1300.     try {
  1301.         // see comment block above for param documentation
  1302.         if (! nsifile.exists())
  1303.             nsifile.create(0x00, 0644);
  1304.         if (optAppendFlag)
  1305.             fstream.init(nsifile, 0x04 | 0x10, 0004, null);
  1306.         else
  1307.             fstream.init(nsifile, 0x02 | 0x20, 0004, null);
  1308.         fstream.write(str, str.length);
  1309.         fstream.close();
  1310.     }
  1311.     catch (e) {
  1312.         if (((typeof nsifile.path) == "string") && 
  1313.                     (nsifile.path.toLowerCase().indexOf("network") != -1))
  1314.             this._logError(false, "WRITE FILE", e, true);
  1315.         else
  1316.             this._logError(false, "WRITE FILE", e, false);
  1317.     }
  1318. },
  1319.  
  1320. getFileFromPath: function (path)
  1321. {
  1322.     return new this._NSIFILE_PATH_C(path);
  1323. },
  1324.  
  1325. deleteFile: function (nsifile)
  1326. {
  1327.     if (! nsifile.exists())
  1328.         return;
  1329.  
  1330.     try {
  1331.         nsifile.remove(false);
  1332.     }
  1333.     catch (e) {
  1334. //        this._logError(false, "DELETE FILE", e, nsifile.path);
  1335.     }
  1336. },
  1337.  
  1338. deleteDirectory: function (nsifile)
  1339. {
  1340.     if (! nsifile.exists())
  1341.         return;
  1342.  
  1343.     try {
  1344.         nsifile.remove(true);
  1345.     } catch (e) {
  1346.         this._logError(false, "DELETE DIRECTORY", e, nsifile.path);
  1347.     }
  1348. },
  1349.  
  1350. getChromeNSIFile: function (chromeURL)
  1351. {
  1352.     var file = null;
  1353.     try {
  1354.         var chromeURI = this._getService(
  1355.                     "@mozilla.org/network/io-service;1",
  1356.                     "nsIIOService")
  1357.                     .newURI(chromeURL, null, null);
  1358.         var fileURL = this._getService(
  1359.                     "@mozilla.org/chrome/chrome-registry;1",
  1360.                     "nsIChromeRegistry")
  1361.                     .convertChromeURL(chromeURI);
  1362.         file = this._getService(
  1363.                     "@mozilla.org/network/protocol;1?name=file",
  1364.                     "nsIFileProtocolHandler")
  1365.                     .getFileFromURLSpec(fileURL.spec);
  1366.     } catch (e) {}
  1367.     return file;
  1368. },
  1369.  
  1370. getResourceNSIFile: function (subdir, filename)
  1371. {
  1372.     if (subdir != null)
  1373.     {
  1374.         subdir = subdir.toString();
  1375.         if (! this._validateFilepathComponent(subdir))
  1376.             return null;
  1377.     }
  1378.     
  1379.     filename = filename.toString();
  1380.     if (! this._validateFilepathComponent(filename))
  1381.         return null;
  1382.     
  1383.     try {
  1384.         var file = this._getService(
  1385.                     "@mozilla.org/file/directory_service;1",
  1386.                     "nsIProperties")
  1387.                     .get("ProfD", this._components.interfaces.nsIFile);
  1388.  
  1389.         file.append("StumbleUpon");
  1390.         if (! file.exists())
  1391.             file.create(file.DIRECTORY_TYPE, 0700);
  1392.         
  1393.         if (subdir != null)
  1394.         {
  1395.             file.append(subdir);
  1396.             if (! file.exists())
  1397.                 file.create(file.DIRECTORY_TYPE, 0700);
  1398.         }
  1399.         
  1400.         file.append(filename);
  1401.     } catch (e) {
  1402.         this._logError(false, "CREATE RESOURCE", e, subdir, filename);
  1403.         return null;
  1404.     }
  1405.     return file;
  1406. },
  1407.  
  1408. getLegacyNSIFile: function (id, optOverrideUserid)
  1409. {
  1410.     var file = this._getService(
  1411.                 "@mozilla.org/file/directory_service;1",
  1412.                 "nsIProperties")
  1413.                 .get("ProfD", this._components.interfaces.nsIFile);
  1414.     var filename;
  1415.     if (optOverrideUserid)
  1416.         filename = id + optOverrideUserid;
  1417.     else
  1418.         filename = id + this._userid;
  1419.     
  1420.     if (! this._validateFilepathComponent(filename))
  1421.         return null;
  1422.     
  1423.     file.append(filename);
  1424.     return file;
  1425. },
  1426.  
  1427. _saveURLResourceToFile: function (url, nsifile)
  1428. {
  1429.     var persist = null;
  1430.     try {
  1431.         persist = this._createInstance(
  1432.                     "@mozilla.org/embedding/browser/nsWebBrowserPersist;1",
  1433.                     "nsIWebBrowserPersist");
  1434.         
  1435.         var nsiuri = this._createInstance(
  1436.                     "@mozilla.org/network/standard-url;1",
  1437.                     "nsIURI");
  1438.         
  1439.         nsiuri.spec = url;
  1440.         persist.progressListener = this;
  1441.         persist.saveURI(nsiuri, null, null, null, null, nsifile);
  1442.     }
  1443.     catch (e) {
  1444.         this._logError(false, "SAVE URI", e, url, nsifile.path);
  1445.         return null;
  1446.     }
  1447.     return persist;
  1448. },
  1449.  
  1450. installResource: function (sourceURL, type, filename, optOverrideTimeout, optForce)
  1451. {
  1452.     var spec = this.lookup("resource_source_url:resource_spec", sourceURL);
  1453.     var queue = this._installResourceQueue; 
  1454.     
  1455.     if (spec && (! optForce))
  1456.         return false;
  1457.     else if (spec && spec.pending)
  1458.         return false;
  1459.     else if (! spec)
  1460.         spec = new Object();
  1461.         
  1462.     spec.sourceURL = sourceURL;
  1463.     spec.type = type;
  1464.     spec.filename = filename;
  1465.     spec.timeout = (optOverrideTimeout) ? optOverrideTimeout : 15000;
  1466.     spec.pending = false;
  1467.     this.define("resource_source_url:resource_spec", spec.sourceURL, spec); 
  1468.  
  1469.     queue.push(spec);
  1470.     
  1471.     this._processInstallResourceQueue();
  1472.     return true;
  1473. },
  1474.  
  1475. _processInstallResourceQueue: function ()
  1476. {
  1477.     this._parent._setTimeout(
  1478.             function (this_) {
  1479.                 this_._processInstallResourceQueue2(); },
  1480.             0,
  1481.             this);
  1482. },
  1483.  
  1484. _processInstallResourceQueue2: function ()
  1485. {
  1486.     var maxConnections = Math.round(this.getValue("network.http.max-connections-per-server") / 2);
  1487.     
  1488.     if (maxConnections < 2)
  1489.         maxConnections = 2;
  1490.     
  1491.     if (    this._installResourcePendingCount >= maxConnections)
  1492.         return;
  1493.     
  1494.     if (this._installResourceQueue.length == 0)
  1495.     {
  1496.         if (this.getValue("#installing_all_avatars"))
  1497.         {
  1498.             this.setValue("$has_avatars", true);
  1499.             this.setValue("#installing_all_avatars", false);
  1500.         }
  1501.         
  1502.         if (this.getValue("#installing_favicons"))
  1503.         {
  1504.             this.setValue("$has_favicons", true);
  1505.             this.setValue("#installing_favicons", false);
  1506.         }
  1507.         
  1508.         this.flushPrefs();
  1509.         
  1510.         return;
  1511.     }
  1512.     
  1513.     var spec = this._installResourceQueue.shift();
  1514.     
  1515.     var file = this.getResourceNSIFile(spec.type, spec.filename);
  1516.     if (! file)
  1517.         return;
  1518.     
  1519.     spec.pending = true;
  1520.     this._installResourcePendingCount++;
  1521.     
  1522.     if (this._parent._logCommunicationEnabled && this._parent._logResourceCFD)
  1523.         su_log("persist resource", spec.sourceURL, spec.type + "/" + spec.filename);
  1524.     
  1525.     var persister = this._saveURLResourceToFile(spec.sourceURL, file); 
  1526.     
  1527.     if (! persister)
  1528.     {
  1529.         spec.pending = false;
  1530.         this._installResourcePendingCount--;
  1531.         return;
  1532.     }
  1533.     
  1534.     this._parent._setTimeout(
  1535.             function (this_, spec, persister) {
  1536.                 this_._abortInstallResource(spec, persister); },
  1537.             spec.timeout,
  1538.             this,
  1539.             spec,
  1540.             persister);
  1541.     
  1542.     return;
  1543. },
  1544.  
  1545. _abortInstallResource: function (spec, persister)
  1546. {
  1547.     if (! spec.pending)
  1548.         return;
  1549.     
  1550.     persister.cancelSave();
  1551.  
  1552.     this._installResourcePendingCount--;
  1553.     
  1554.     this._processInstallResourceQueue();
  1555. },
  1556.  
  1557. isResourceInstalled: function (type, filename)
  1558. {
  1559.     var file = this.getResourceNSIFile(type, filename);
  1560.     
  1561.     return file && file.exists();
  1562. },
  1563.  
  1564. deleteResource: function (type, filename)
  1565. {
  1566.     this.deleteFile(this.getResourceNSIFile(type, filename));
  1567. },
  1568.  
  1569. getResourceURLFromSourceURL: function (sourceURL)
  1570. {
  1571.     var spec = this.lookup("resource_source_url:resource_spec", sourceURL);
  1572.     
  1573.     if (! spec)
  1574.         return null;
  1575.     
  1576.     return this.getResourceURLFromName(spec.type, spec.filename);
  1577. },
  1578.  
  1579. getResourceURLFromName: function (type, name)
  1580. {
  1581.     var file = this.getResourceNSIFile(type, name);
  1582.     var protocol = this._createInstance(
  1583.                 "@mozilla.org/network/protocol;1?name=file",
  1584.                 "nsIFileProtocolHandler");
  1585.  
  1586.     if (file)
  1587.         return protocol.getURLSpecFromFile(file);
  1588.     else
  1589.         return null;
  1590. },
  1591.  
  1592. hasFeature: function (name, optBits)
  1593. {
  1594.     var bits;
  1595.     if (optBits)
  1596.         bits = optBits;
  1597.     else if (name.charAt(0) == "$")
  1598.         bits = this.getValue("$form");
  1599.     else if (name.charAt(0) == "@")
  1600.         bits = this.getValue("@client_form");
  1601.     var mask = this.getFeatureMask(name);
  1602.     return ((bits & mask) == mask);
  1603. },
  1604.  
  1605. getFeatureMask: function (name)
  1606. {
  1607.     return this.lookup("featureid:bitmask", name);
  1608. },
  1609.  
  1610. enableFeature: function (name)
  1611. {
  1612.     var prefName;
  1613.     if (name.charAt(0) == "$")
  1614.         prefName = "$form";
  1615.     else if (name.charAt(0) == "@")
  1616.         prefName = "@client_form";
  1617.  
  1618.     var mask = this.getFeatureMask(name);
  1619.     var bits = this.getValue(prefName);
  1620.     this.setValue(prefName, (bits | mask));
  1621. },
  1622.  
  1623. disableFeature: function (name)
  1624. {
  1625.     var prefName;
  1626.     if (name.charAt(0) == "$")
  1627.         prefName = "$form";
  1628.     else if (name.charAt(0) == "@")
  1629.         prefName = "@client_form";
  1630.  
  1631.     var mask = this.getFeatureMask(name);
  1632.     var bits = this.getValue(prefName);
  1633.     this.setValue(prefName, (bits & (~ mask)));
  1634. },
  1635.  
  1636. // Required by a routine in migrate.js
  1637. migrateToContacts: function ()
  1638. {
  1639.     // Move data from $friends, $emails and $sendto_stats into 
  1640.     // $contacts.
  1641.  
  1642.     var friendsStr = this.getValue("$friends");
  1643.     if ((friendsStr != "") && (friendsStr != "FRIEND"))
  1644.         this.updateLegacyFriend(friendsStr);
  1645.     
  1646.     var emails;
  1647.     if (this.isPrefDefined("$emails"))
  1648.         emails = this.getValue("$emails").split("\t");
  1649.     else
  1650.         emails = new Array();
  1651.     
  1652.     var i;
  1653.     
  1654.     var contact;
  1655.     for (i = emails.length - 1; i >= 0; i--)
  1656.     {
  1657.         if (emails[i] == "")
  1658.             continue;
  1659.         
  1660.         contact = this.selectRow("contact", "email", emails[i]);
  1661.         if (! contact)
  1662.         {
  1663.             contact = new Object();
  1664.             contact.email = emails[i];
  1665.             this.insertRow("contact", contact);
  1666.         }
  1667.     }
  1668.     
  1669.     
  1670.     var sends;
  1671.     if (this.isPrefDefined("$sendto_stats"))
  1672.         sends = this.getValue("$sendto_stats").split("\n");
  1673.     else if (this.isPrefDefined("$sendtos"))
  1674.         sends = this.getValue("$sendtos").split("\n");
  1675.     else
  1676.         sends = new Array();
  1677.     
  1678.     var artificialTimestamp = 1;
  1679.     for (i = sends.length - 1; i >= 0; i--)
  1680.     {
  1681.         if (sends[i] == "")
  1682.             continue;
  1683.         
  1684.         var fields = sends[i].split("\t");
  1685.         if (fields.length == 2)
  1686.         {
  1687.             // Migrate pre-2.7 data to include the 'type' field. -- JW
  1688.             fields.unshift("friend");
  1689.         }
  1690.         if (fields[0] == "friend")
  1691.         {
  1692.             contact = this.selectRow("contact", "nickname", fields[1]);
  1693.             if (! contact)
  1694.             {
  1695.                 contact = new Object();
  1696.                 contact.nickname = fields[i];
  1697.                 this.insertRow("contact", contact);
  1698.             }
  1699.         }
  1700.         else if (fields[0] == "email")
  1701.         {
  1702.             contact = this.selectRow("contact", "email", fields[1]);
  1703.             if (! contact)
  1704.             {
  1705.                 contact = new Object();
  1706.                 contact.email = fields[i];
  1707.                 contact.hidden = true;
  1708.                 this.insertRow("contact", contact);
  1709.             }
  1710.         }
  1711.         contact.referral_count = parseInt(fields[2]);
  1712.         contact.referral_timestamp = artificialTimestamp;
  1713.         artificialTimestamp++;
  1714.     }
  1715. },
  1716.  
  1717. // Required by this.migrateToContacts() 
  1718. updateLegacyFriend: function (commandStr)
  1719. {
  1720.     var nicks = commandStr.split(" ");
  1721.     nicks.shift();
  1722.     var mutuals = new Object();
  1723.     var i;
  1724.     var contact;
  1725.     for (i = 0; i < nicks.length; i++)
  1726.     {
  1727.         mutuals[nicks[i]] = true;
  1728.         contact = this.selectRow("contact", "nickname", nicks[i]);
  1729.         if (! contact)
  1730.         {
  1731.             contact = new Object();
  1732.             contact.nickname = nicks[i];
  1733.             this.insertRow("contact", contact);
  1734.         }
  1735.     }
  1736.     
  1737.     var contacts = this.getValue("$contacts");
  1738.     for (i = 0; i < contacts.length; i++)
  1739.     {
  1740.         if ((typeof (contacts[i])) == "undefined")
  1741.         {
  1742.             this._logError(false, "LEGACY FRIEND");
  1743.             contacts.splice(i, 1);
  1744.             i--;
  1745.             continue;
  1746.         }
  1747.  
  1748.         if ((typeof (contacts[i].nickname)) != "undefined")
  1749.         {
  1750.             if (mutuals[contacts[i].nickname])
  1751.                 contacts[i].mutual = 1;
  1752.             else
  1753.                 contacts[i].mutual = 0;
  1754.             
  1755.             this.updateRow(contacts[i]);
  1756.         }
  1757.     }
  1758. },
  1759.  
  1760. _dispatchEvent: function (eventType, optionalEvent)
  1761. {
  1762.     var listeners = this.eventListenerListsByEventId[eventType];
  1763.     if (! listeners)
  1764.         return;
  1765.     
  1766.     var i;
  1767.     for (i = 0; i < listeners.length; i++)
  1768.     {
  1769.         var event;
  1770.         if (optionalEvent)
  1771.             event = this.deserialize(this.serialize(optionalEvent, false));
  1772.         
  1773.         event.target = this;
  1774.         event.eventName = eventType;
  1775.         listeners[i](event);
  1776.     }
  1777. },
  1778.  
  1779. addEventListener: function (eventType, listener)
  1780. {
  1781.     var listeners = this.eventListenerListsByEventId[eventType];
  1782.     if (! listeners)
  1783.     {
  1784.         listeners = new Array();
  1785.         this.eventListenerListsByEventId[eventType] = listeners;
  1786.     }
  1787.     else
  1788.     {
  1789.         this.removeEventListener(eventType, listener);
  1790.     }
  1791.     listeners.push(listener);
  1792. },
  1793.  
  1794. removeEventListener: function (eventType, listener)
  1795. {
  1796.     var listeners = this.eventListenerListsByEventId[eventType];
  1797.     var i;
  1798.     for (i = 0; i < listeners.length; i++)
  1799.     {
  1800.         if (listener == listeners[i])
  1801.         {
  1802.             listeners = listeners.splice(i, 1);
  1803.             break;
  1804.         }
  1805.     }
  1806. },
  1807.  
  1808. _getErrorObjectDump: function (o)
  1809. {
  1810.     if (! o)
  1811.         return "\n" + (typeof o);
  1812.     
  1813.     var str = "\n===== dump ===\n"; 
  1814.     var p;
  1815.     for (p in o)
  1816.     {
  1817.         if (p.match(/.*_ERR$/))
  1818.             continue;
  1819.         
  1820.         try {
  1821.             str += "[" + p + "]\n" + o[p] + "\n";
  1822.         }
  1823.         catch (e) {
  1824.             str += "[" + p + "] ERROR\n" + e + "\n";
  1825.         }
  1826.     }
  1827.     str += "========";
  1828.     return str;
  1829. },
  1830.  
  1831. _logError: function ()
  1832. {
  1833.     var i;
  1834.     var str = "";
  1835.     for (i = 1; i < arguments.length; i++)
  1836.     {
  1837.         var type = typeof(arguments[i]);
  1838.         if ((i == 2) && (type != "string") && (type != "number"))
  1839.             str += this._getErrorObjectDump(arguments[i]);
  1840.         
  1841.         else
  1842.             str += "\n" + arguments[i];
  1843.     }
  1844.     
  1845.     if (arguments[0])
  1846.         this.globals.batched_pref_error_log += (this.globals.batched_pref_error_log == "") ? str : ("\n" + str);
  1847.     else
  1848.         this.globals.batched_error_log += (this.globals.batched_error_log == "") ? str : ("\n" + str);
  1849. },
  1850.  
  1851. getThruDomainChannels: function (sorted)
  1852. {
  1853.     // The current implementation always returns sorted. -- JW
  1854.     
  1855.     if (this._sortedThruChannels)
  1856.         return this._sortedThruChannels;
  1857.     
  1858.     try {
  1859.     
  1860.     var i;
  1861.     var channels = this.selectAllRows("dyn_channel");
  1862.     this._channelsByDomain = new Object();
  1863.     
  1864.     if (! channels.length)
  1865.         return null;
  1866.     
  1867.     for (i = 0; i < channels.length; i++)
  1868.     {
  1869.         channels[i].sort_name = channels[i].name.toLowerCase().replace(/\./g, "");
  1870.         this._channelsByDomain[channels[i].domain] = channels[i];
  1871.     }
  1872.     channels.sort(function (a, b)
  1873.                 {
  1874.                     if ( a.sort_name > b.sort_name ) return 1;
  1875.                     if ( a.sort_name < b.sort_name ) return -1;
  1876.                     return 0;
  1877.                 });
  1878.     
  1879.     this._sortedThruChannels = channels;
  1880.         
  1881.     } catch (e) {}
  1882.     
  1883.     return this._sortedThruChannels;
  1884. },
  1885.  
  1886. getThruDomainChannel: function (domain)
  1887. {
  1888.     if (! this._channelsByDomain)
  1889.         return null;
  1890.  
  1891.     if (! this._channelsByDomain[domain])
  1892.         return null;
  1893.     
  1894.     return this._channelsByDomain[domain];
  1895. },
  1896.  
  1897. isThruDomain: function (domain)
  1898. {
  1899.     if (! this._channelsByDomain)
  1900.         return null;
  1901.  
  1902.     return (this._channelsByDomain[domain]) ? true : false;
  1903. },
  1904.  
  1905. getBMTagFromTag: function (str)
  1906. {
  1907.     return str.replace(/\-/g, " ");
  1908. },
  1909.  
  1910. getBMTagFromCatid: function (cat)
  1911. {
  1912.     if (! this._bmcattags)
  1913.     {
  1914.         if (! this._catnums)
  1915.             this._loadTopicTree();
  1916.         
  1917.         this._bmcattags = new Array();
  1918.         var i;
  1919.         var tmp;
  1920.         var bmtag;
  1921.         var num;
  1922.         for (i = 0; i < this._catnums.length; i++)
  1923.         {
  1924.             num = this._catnums[i];
  1925.             bmtag = this._tagnames[num];
  1926.             
  1927.             tmp = this.lookup("topic_tag:bookmark_topic_tag", bmtag);
  1928.             if (tmp)
  1929.                 bmtag = tmp;
  1930.             
  1931.             this._bmcattags[num] = bmtag.replace(/\-/g, " ");
  1932.         }
  1933.     }
  1934.     
  1935.     if (this._bmcattags[cat])
  1936.         return this._bmcattags[cat];
  1937.     else
  1938.         return null;
  1939. },
  1940.  
  1941. _loadTopicTree: function ()
  1942. {
  1943.     this._dicts["catid:topic_name"] = new Array();  // legacy type
  1944.     this._dicts["topic_name:catid"] = new Object();
  1945.     this._dicts["catid:folder_name"] = new Array(); // legacy type
  1946.     this._dicts["catid:x_flag"] = new Object();
  1947.     this._foldernames = new Array();
  1948.     this._catnums = new Array();
  1949.     this._tagnames = new Array();
  1950.  
  1951.     var nsiuri = this._createInstance(
  1952.                 "@mozilla.org/network/standard-url;1",
  1953.                 "nsIURI");
  1954.     nsiuri.spec = "chrome://stumbleupon/content/topics.csv";
  1955.     var catdata = this.readURI(nsiuri);
  1956.  
  1957.     // Parse it into an array
  1958.     var folder = '';
  1959.     var folders = new Array();
  1960.     var splitseen = catdata.split("\n");
  1961.     for (var i = 0; i < splitseen.length; i++)
  1962.     {
  1963.         if (splitseen[i] == "")
  1964.             continue;
  1965.         
  1966.         var line = splitseen[i];
  1967.         var lines = line.split(",");
  1968.         var num = parseInt(lines[0]);
  1969.         var name = lines[1];
  1970.         if (lines[2] != "")
  1971.         {        
  1972.             folder = lines[2];
  1973.             this._dicts["catid:folder_name"][num] = folder;
  1974.             if (! folders[folder])
  1975.             {
  1976.                 folders[folder] = 1;
  1977.                 this._foldernames.push(folder);
  1978.             }
  1979.         }
  1980.         this._catnums.push(num);
  1981.         if (lines[3] == "P")
  1982.             this._dicts["catid:x_flag"][num] = 1;
  1983.         if (lines[4] != "")
  1984.             this._tagnames[num] = lines[4];
  1985.         this._dicts["catid:topic_name"][num] = name;
  1986.         this._dicts["topic_name:catid"][name] = num;
  1987.     }
  1988.  
  1989.     this._foldernames.sort();
  1990. },
  1991.  
  1992. getAlphaSupertopicNames: function ()
  1993. {
  1994.     if (! this._foldernames)
  1995.         this._loadTopicTree();
  1996.     
  1997.     return this._foldernames;
  1998. },
  1999.  
  2000. refreshAvatar: function (contactid)
  2001. {
  2002.     var filename = contactid + ".jpg";
  2003.     
  2004.     this.removeFromCache("http://cdn.stumble-upon.com/iconpics/" + filename);
  2005.     this.removeFromCache("http://cdn.stumble-upon.com/mainpics/" + filename);
  2006.     this.removeFromCache("http://cdn.stumble-upon.com/mediumpics/" + filename);
  2007.     this.removeFromCache("http://cdn.stumble-upon.com/superminipics/" + filename);
  2008.     
  2009.     return this.installResource(
  2010.                 "http://cdn.stumble-upon.com/iconpics/" + filename,
  2011.                 "iconpics",
  2012.                 filename);
  2013. },
  2014.  
  2015. removeFromCache: function (url) 
  2016. {
  2017.     var session = this._getService(
  2018.                 "@mozilla.org/network/cache-service;1",
  2019.                 "nsICacheService")
  2020.                 .createSession("HTTP", 0, true);
  2021.     
  2022.     session.doomEntriesIfExpired = false;
  2023.  
  2024.     try {
  2025.         session.asyncOpenCacheEntry(
  2026.                     url,
  2027.                     Components.interfaces.nsICache.ACCESS_WRITE,
  2028.                     this);
  2029.     } catch (e) {}
  2030. },
  2031.  
  2032. // returns a salted, hashed, encoded password
  2033. //!!! We want to transition to storing unencoded password in prefs,
  2034. //    but to mitigate risk, that change is deferred until after the
  2035. //    FF3 release. -- JW
  2036. getEncodedPassword: function (password, user_salt)
  2037. {
  2038.     return encodeURIComponent(this._parent.getSha1(this.getValue("~password_app_salt") + user_salt + password));
  2039. },
  2040.  
  2041. // used by getStoredPassword, by signinDialog, by 
  2042. // handle_change_password and by su_init_new_user to save the password
  2043. storePassword: function (password, unhashedPassword)
  2044. {
  2045.     var passwordManager = this._createInstance(
  2046.                 "@mozilla.org/passwordmanager;1",
  2047.                 "nsIPasswordManager");
  2048.  
  2049.     if (this._parent.getHostSpec().sha1)
  2050.     {
  2051.         if (this.getValue("@enable_secure_store_auth"))
  2052.         {
  2053.             try {
  2054.                 // The api doesn't define a method to modify an entry (ref:
  2055.                 // Firefox 1.5). -- JW
  2056.                 passwordManager.removeUser(this.getValue("~password_store_key"), this._userid);
  2057.             } catch (e) {}
  2058.  
  2059.             try {
  2060.                 passwordManager.addUser(this.getValue("~password_store_key"), this._userid, password);
  2061.             } catch (e) { this._logError(false, "PASSWORD MANAGER SAVE ERROR", e);
  2062.                 return;
  2063.             }
  2064.             
  2065.             if (this.isPrefDefined("$token"))
  2066.                 this.clearPref("$token");
  2067.     
  2068.             if (this.isPrefDefined("$password"))
  2069.                 this.clearPref("$password");
  2070.         }
  2071.         else
  2072.         {
  2073.             this.setValue("$token", password);
  2074.             this.flushPrefs();
  2075.  
  2076.             if (this.isPrefDefined("$password"))
  2077.             {
  2078. //                if (unhashed_password)
  2079. //                    this.setValue("$password", unhashed_password); 
  2080.                 this.clearPref("$password");
  2081.             }
  2082.             try {
  2083.                 // The api doesn't define a method to modify an entry (ref:
  2084.                 // Firefox 1.5). -- JW
  2085.                 passwordManager.removeUser(this.getValue("~password_store_key"), this._userid);
  2086.             } catch (e) {}
  2087.         }
  2088.     }
  2089.     else
  2090.     {
  2091.         if (unhashedPassword != null)
  2092.             this.setValue("$password", unhashedPassword);
  2093.         this.flushPrefs();
  2094.     }
  2095. },
  2096.  
  2097. // used by init_login and the global change-password event handler to
  2098. // get the stored password; handles migration to hashed password
  2099. getStoredPassword: function ()
  2100. {
  2101.     var password = null;
  2102.     
  2103.     if (this._userid == "")
  2104.         return null;
  2105.     
  2106.     var host = {value:""};
  2107.     var user =  {value:""};
  2108.     var tmpPassword = {value:""};
  2109.  
  2110.     if (this.isPrefDefined("$token"))
  2111.         password = this.getValue("$token");
  2112.  
  2113.     if (((! password) || (password == "")) && this.isPrefDefined("$password"))
  2114.         password = this.getValue("$password");
  2115.  
  2116.     if ((! password) || (password == ""))
  2117.     {
  2118.         var passwordManager = this._createInstance(
  2119.                     "@mozilla.org/passwordmanager;1",
  2120.                     "nsIPasswordManagerInternal");
  2121.  
  2122.         try {
  2123.             passwordManager.findPasswordEntry(this.getValue("~password_store_key"), this._userid, null, host, user, tmpPassword);
  2124.             password = tmpPassword.value;
  2125.         } catch (e) {}
  2126.     }
  2127.  
  2128.     if (this._parent.getHostSpec().sha1 && 
  2129.                 ((typeof password) != "undefined") && (password != null) &&
  2130.                 (password.length < 28))
  2131.     {
  2132.         password = this.getEncodedPassword(password, this._userid);
  2133.     }
  2134.     
  2135.     if (((typeof password) != "undefined") && (password != null))
  2136.         this.storePassword(password, null);
  2137.  
  2138.     return password;
  2139. },
  2140.  
  2141. // used by su_logout to delete the stored password
  2142. deleteStoredPassword: function ()
  2143. {
  2144.     if (this.isPrefDefined("$token"))
  2145.         this.clearPref("$token");
  2146.  
  2147.     if (this.isPrefDefined("$password"))
  2148.         this.clearPref("$password");
  2149.  
  2150.     var passwordManager = this._createInstance(
  2151.                 "@mozilla.org/passwordmanager;1",
  2152.                 "nsIPasswordManager");
  2153.  
  2154.     try {
  2155.         passwordManager.removeUser(this.getValue("~password_store_key"), this._userid);
  2156.     } catch (e) {}
  2157. },
  2158.  
  2159. QueryInterface: function (iid)
  2160. {
  2161.     if (iid.equals(this._components.interfaces.nsIWebProgressListener) ||
  2162.             iid.equals(this._components.interfaces.nsISupportsWeakReference) ||
  2163.             iid.equals(this._components.interfaces.nsISupports) ||
  2164.             iid.equals(this._components.interfaces.nsICacheListener) ||
  2165.             iid.equals(this._components.interfaces.nsIWindowMediatorListener))
  2166.         return this;
  2167.     else
  2168.         throw this._components.errors.NS_ERROR_NO_INTERFACE;
  2169.  
  2170. },
  2171.  
  2172. onLocationChange: function(aWebProgress, aRequest, aLocation) {},
  2173.  
  2174. onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
  2175.  
  2176. onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
  2177. {
  2178.     const nsiwpl = this._components.interfaces.nsIWebProgressListener;
  2179.  
  2180.     if (aRequest && (aStateFlags & nsiwpl.STATE_STOP))
  2181.     {
  2182.         var event = new Object();
  2183.         event.URL = aRequest.name;
  2184.         var spec = this.lookup("resource_source_url:resource_spec", event.URL);
  2185.         
  2186.         if (spec && spec.pending)
  2187.         {
  2188.             spec.pending = false;
  2189.             this._installResourcePendingCount--;
  2190.             this._processInstallResourceQueue();
  2191.         }
  2192.         
  2193.         if (this._parent._logCommunicationEnabled && this._parent._logResourceCFD)
  2194.             su_log("resourceinstalled", event.URL);
  2195.         
  2196.         this._dispatchEvent("resourceinstalled", event);
  2197.     }
  2198. },
  2199.  
  2200. onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
  2201.  
  2202. onSecurityChange: function(aWebProgress, aRequest, aState) {},
  2203.  
  2204. onCacheEntryAvailable: function(descriptor, accessGranted, status)
  2205. {
  2206.     try {
  2207.         descriptor.doom();
  2208.         descriptor.close();
  2209.     } catch(e) {}
  2210. },
  2211.  
  2212. onCloseWindow: function (win)
  2213. {
  2214.     var o = win.docShell.QueryInterface(this._components.interfaces.nsIWebNavigation);
  2215.     if (o && o.document && o.document.documentURI &&
  2216.             (o.document.documentURI.indexOf("chrome://stumbleupon/content/discoveryDialog.xul") == 0))
  2217.     {
  2218.         var event = new Object();
  2219.         event.URL = o.document.documentURI;
  2220.         this._dispatchEvent("discdlgclose", event);
  2221.     }
  2222. },
  2223.  
  2224. onOpenWindow: function (win) {},
  2225.  
  2226. onWindowTitleChange: function (win) {},
  2227.  
  2228. //Code to upgrade database from 1 version to another one
  2229. //When modifying schema for an upgrade :
  2230. //1/ Increment "su_current_schema_version" number
  2231. //2/ Add an entry in the switch (dbVersion) with the previous db version
  2232. // and add all your sql statements into the upgradeQuery array.
  2233. //Then the upgrade will be done automatically by running all the needed queries
  2234. //depending on the previuos db schema version
  2235. currentSchemaVersion: 5,
  2236.  
  2237. //functions to upgrade user database from an older version when needed
  2238. _upgradeProfileDB: function()
  2239. {
  2240.     var dbVersion = 1;
  2241.     
  2242.     if (this._userdb.tableExists("settings"))
  2243.         dbVersion = parseInt(this._userdb.valueQuery("select value from settings where name = 'schema_version'"));
  2244.     
  2245.     // No need to upgrade
  2246.     if (dbVersion == this.currentSchemaVersion)
  2247.         return;
  2248.     
  2249.     var upgradeQueries = new Array();
  2250.     switch (dbVersion)
  2251.     {
  2252.         case 1:
  2253.             upgradeQueries.push("CREATE TABLE IF NOT EXISTS settings (name TEXT PRIMARY KEY, value TEXT);");
  2254.         case 2:
  2255.             upgradeQueries.push("DROP TABLE IF EXISTS blocked_domains;");
  2256.             upgradeQueries.push("CREATE TABLE IF NOT EXISTS blocked_domain (domain TEXT, modified INT, active INT, PRIMARY KEY (domain) ON CONFLICT REPLACE);");
  2257.             upgradeQueries.push("CREATE TABLE IF NOT EXISTS command_queue ( seqid INTEGER PRIMARY KEY AUTOINCREMENT, priority INT, command TEXT );");
  2258.             upgradeQueries.push("CREATE INDEX IF NOT EXISTS command_queue__priority ON command_queue ( priority DESC, seqid );");
  2259.         case 3:
  2260.             upgradeQueries.push("CREATE INDEX IF NOT EXISTS url_map__urlid ON url_map ( urlid );");
  2261.         case 4:
  2262.             upgradeQueries.push("CREATE TABLE IF NOT EXISTS stumble_visited_urls (" +
  2263.                                 "publicid TEXT," +
  2264.                                 "stumbletime INT," +
  2265.                                 "referralid TEXT DEFAULT ''," +
  2266.                                 "retrycount INT DEFAULT 0," +
  2267.                                 "PRIMARY KEY (publicid, referralid) ON CONFLICT REPLACE);");
  2268.             upgradeQueries.push("CREATE INDEX IF NOT EXISTS stumble_visited_urls__stumbletime ON stumble_visited_urls( stumbletime );");
  2269.  
  2270.     }
  2271.     
  2272.     // Update schema number
  2273.     upgradeQueries.push("DELETE FROM settings where name = 'schema_version';");
  2274.     upgradeQueries.push("INSERT INTO settings values ('schema_version', " + this.currentSchemaVersion + ");");
  2275.     
  2276.     this._userdb.beginTransaction();
  2277.     for each (query in upgradeQueries)
  2278.         this._userdb._getDBConnection().executeSimpleSQL(query);
  2279.     this._userdb.commitTransaction();
  2280. },
  2281.  
  2282. _initConstants: function ()
  2283. {
  2284.     this._dicts["lang_code:language"] = su_const_a;
  2285.     this._dicts["nickname:bad_nick_flag"] = su_const_b;
  2286.     this._dicts["userid:uc_logger_flag"] = su_const_c;
  2287.     this._dicts["toolbarid:bad_target_flag"] = su_const_d;
  2288.     this._dicts["domain:info_message"] = su_const_e;
  2289.     this._dicts["domain:info_message_simple"] = su_const_f;
  2290.     this._dicts["domain:tomore_favicon_list"] = su_const_g;
  2291.     this._dicts["state:poll_interval_s"] = su_const_h;
  2292.     this._dicts["topic_tag:bookmark_topic_tag"] = su_const_i;
  2293.     this._dicts["featureid:bitmask"] = su_const_feature_bits;
  2294.     this._dicts["stumblereportretrycount:timeout"] = su_const_stumble_report_timeouts_s;
  2295.      
  2296.     this._TABLE_IDS_BY_NAME = su_const_tables;
  2297.     
  2298.     // Note that we don't support using lookup() to acquire default
  2299.     // values.  Clients who need a default value should use
  2300.     // getDefaultValue().
  2301.     this._DEFAULTS_BY_ID = su_const_defaults;
  2302. }
  2303.  
  2304.  
  2305.  
  2306. } // END prototype
  2307.  
  2308. // "lang_code:language" dictionary
  2309. const su_const_a = {
  2310. "AR":"Arabic",
  2311. "EU":"Basque",
  2312. "BN":"Bengali",
  2313. "BG":"Bulgarian",
  2314. "ZH":"Chinese",
  2315. "CA":"Catalan",
  2316. "HR":"Croatian", 
  2317. "CS":"Czech",
  2318. "NL":"Dutch",
  2319. "EN":"English",
  2320. "EO":"Esperanto",
  2321. "ET":"Estonian",
  2322. "FA":"Farsi",
  2323. "FI":"Finnish",
  2324. "FR":"French",
  2325. "DA":"Danish",
  2326. "DE":"German",
  2327. "EL":"Greek",
  2328. "HE":"Hebrew",
  2329. "HI":"Hindi",
  2330. "HU":"Hungarian",
  2331. "IS":"Icelandic",
  2332. "ID":"Indonesian",
  2333. "IT":"Italian",
  2334. "JA":"Japanese",
  2335. "KO":"Korean",
  2336. "LT":"Lithuanian",
  2337. "LV":"Latvian",
  2338. "MK":"Macedonian",
  2339. "NO":"Norwegian",
  2340. "PL":"Polish",
  2341. "PT":"Portuguese",
  2342. "RO":"Romanian",
  2343. "RU":"Russian",
  2344. "SR":"Serbian",
  2345. "SK":"Slovak",
  2346. "SL":"Slovenian",
  2347. "ES":"Spanish",
  2348. "SV":"Swedish",
  2349. "TH":"Thai",
  2350. "TR":"Turkish",
  2351. "VI":"Vietnamese"};
  2352.  
  2353. // "nickname:bad_nick_flag" dictionary
  2354. const su_const_b = {
  2355. "about":1,
  2356. "backup":1,
  2357. "blog":1,
  2358. "bug":1,
  2359. "bugs":1,
  2360. "bugzilla":1,
  2361. "business":1,
  2362. "buzz":1,
  2363. "community":1,
  2364. "dating":1,
  2365. "facebook":1,
  2366. "feeds":1,
  2367. "forum":1,
  2368. "friends":1,
  2369. "ftp":1,
  2370. "group":1,
  2371. "groups":1,
  2372. "image":1,
  2373. "images":1,
  2374. "img":1,
  2375. "irc":1,
  2376. "lab":1,
  2377. "labs":1,
  2378. "m":1,
  2379. "mail":1,
  2380. "match":1,
  2381. "matches":1,
  2382. "matchmaker":1,
  2383. "mov":1,
  2384. "movie":1,
  2385. "movies":1,
  2386. "nickname":1,
  2387. "people":1,
  2388. "pic":1,
  2389. "pics":1,
  2390. "pop":1,
  2391. "pop3":1,
  2392. "relationship":1,
  2393. "relationships":1,
  2394. "reviews":1,
  2395. "rss":1,
  2396. "search":1,
  2397. "secure":1,
  2398. "server1":1,
  2399. "smtp":1,
  2400. "squirt":1,
  2401. "ssl":1,
  2402. "static":1,
  2403. "stumble":1,
  2404. "stumbler":1,
  2405. "stumblers":1,
  2406. "stumbles":1,
  2407. "su":1,
  2408. "tips":1,
  2409. "toolbar":1,
  2410. "v":1,
  2411. "vid":1,
  2412. "video":1,
  2413. "videos":1,
  2414. "vids":1,
  2415. "w":1,
  2416. "webservice":1,
  2417. "webservices":1,
  2418. "webmail":1,
  2419. "wii":1,
  2420. "ww":1,
  2421. "www":1,
  2422. "www1":1,
  2423. "www2":1,
  2424. "www3":1,
  2425. "wwww":1};
  2426.  
  2427. // "userid:uc_logger_flag" dictionary
  2428. const su_const_c = {
  2429. "1":1,
  2430. "2":1,
  2431. "3":1,
  2432. "7":1,
  2433. "27":1,
  2434. "74208":1,
  2435. "728238":1,
  2436. "1279921":1,
  2437. "1329486":1,
  2438. "1427242":1,
  2439. "1461473":1,
  2440. "1477154":1,
  2441. "1693643":1, 
  2442. "1764575":1,
  2443. "1940576":1,
  2444. "2326041":1,
  2445. "2441706":1,
  2446. "2461565":1,
  2447. "2562486":1,
  2448. "2894556":1,
  2449. "3166398":1,
  2450. "3432487":1,
  2451. "3661073":1,
  2452. "4176101":1,
  2453. "4504773":1,
  2454. "5584898":1,
  2455. "5785666":1,
  2456. "5805687":1};
  2457.  
  2458. // "toolbarid:bad_target_flag" dictionary
  2459. const su_const_d = {
  2460. "FindToolbar":1,
  2461. "linktoolbar":1,
  2462. "main-menubar":1,
  2463. "fbToolbar":1,
  2464. "anontoolbar":1,
  2465. "MyWebSearch":1,
  2466. "toronto_blue_jays":1,
  2467. "yahoo-toolbar":1,
  2468. "webpedia":1};
  2469.  
  2470. // "domain:info_message" dictionary
  2471. const su_const_e = {
  2472. "wikipedia.org":"Explore a world of knowledge and oddities in the Wikipedia channel.",
  2473. "flickr.com":"See the best of the best pics in the Flickr channel.",
  2474. "myspace.com":"Stumble through music, peeps and more with the Myspace channel.",
  2475. "youtube.com":"Your personalized Youtube channel learns what you like to watch.",
  2476. "blogspot.com":"View slices of life in the Blogspot channel.",
  2477. "wordpress.com":"Teleport to quality sectors of the blogosphere via your Wordpress channel.",
  2478. "theonion.com":"Stumble through classic irreverance in The Onion channel.",
  2479. "pbs.org":"Browse multimedia and more in the PBS channel.",
  2480. "physorg.com":"Travel the frontier of sci-tech in the PhysOrg channel.",
  2481. "cnn.com":"Check your personalized CNN channel for mainstream news.",
  2482. "bbc.co.uk":"Stay informed and entertained with news, TV and radio from the Beeb.",
  2483. ".gov":"Taste some tangy fruits of government in the US Gov channel.",
  2484. ".edu":"Explore art and craft, PHD-style in the university channel.",
  2485. "break.com":"Skip to the good stuff using your personalized Break.com channel.",
  2486. "metacafe.com":"Stumble through the Metacafe channel to see the highest-rated videos.",
  2487. "wired.com":"Catch the latest tech trends in the Wired channel."};
  2488.  
  2489. // "domain:info_message_simple" dictionary
  2490. const su_const_f = {
  2491. "flickr.com":"Click here to Stumble thru Flickr pages.",
  2492. "blogspot.com":"Click here to Stumble thru Blogspot blogs.",
  2493. "wordpress.com":"Click here to Stumble thru Wordpress blogs.",
  2494. "physorg.com":"Click here to Stumble thru PhysOrg articles.",
  2495. ".gov":"Click here to Stumble thru US Gov sites.",
  2496. ".edu":"Click here to Stumble thru university sites."};
  2497.  
  2498. // "domain:tomore_favicon_list" dictionary
  2499. const su_const_g = {
  2500. "wikipedia.org":"cnn.com,pbs.org,youtube.com",
  2501. "flickr.com":"youtube.com,myspace.com,theonion.com",
  2502. "myspace.com":"youtube.com,flickr.com,theonion.com",
  2503. "youtube.com":"youtube.com,myspace.com,wikipedia.org",
  2504. "blogspot.com":"wordpress.com,youtube.com,flickr.com",
  2505. "wordpress.com":"blogspot.com,youtube.com,flickr.com",
  2506. "theonion.com":"youtube.com,blogspot.com,flickr.com",
  2507. "pbs.org":"wikipedia.org,bbc.co.uk,youtube.com",
  2508. "physorg.com":"cnn.com,wired.com,youtube.com",
  2509. "cnn.com":"bbc.co.uk,wikipedia.org,youtube.com",
  2510. "bbc.co.uk":"cnn.com,wikipedia.org,youtube.com",
  2511. ".gov":"wikipedia.org,cnn.com,youtube.com",
  2512. ".edu":"wikipedia.org,cnn.com,youtube.com"};
  2513.  
  2514. // "state:poll_interval_s" dictionary
  2515. const su_const_h = {
  2516. "a":28800,  // 8h   never sent or received a stumble
  2517. "b":10,     // 10s  sent a referral
  2518. "c":20,     // 20s  from 'b' upon check
  2519. "d":30,     // 30s  from 'c' upon check
  2520. "e":30,     // 30s  from 'd' upon check
  2521. "f":180,    // 3m   from 'e' upon check
  2522. "g":64800,  // 18h  10 days since last stumble, rate, send, receive or mail-notify
  2523. "h":604800, // 1wk  2 months since last stumble, rate, send, receive or mail-notify
  2524. "i":900,    // 15m  contingency; set via server command
  2525. "j":1800,   // 30m  contingency; set via server command
  2526. "k":3600,   // 1h   contingency; set via server command
  2527. "l":14400}; // 4h   contingency; set via server command
  2528.  
  2529. // "topic_tag:bookmark_topic_tag" dictionary
  2530. const su_const_i = {
  2531. "c-a-d":"cad",
  2532. "children-s-books":"childrens-books",
  2533. "dj-s-mixing":"djs-mixing",
  2534. "int-l-development":"intl-development",
  2535. "men-s-issues":"mens-issues",
  2536. "women-s-issues":"womens-issues"};
  2537.  
  2538. // "featureid:bitmask" dictionary
  2539. const su_const_feature_bits = {
  2540. "$sociallinks":             0x00000001,
  2541. "$tagger":                  0x00000002, // reclaimable (was freereporting)
  2542. "$mediareporting":          0x00000004, // reclaimable
  2543. "$sync":                    0x00000008, // unusable
  2544. "$info_tutorial":           0x00000010,
  2545. "$reportoption":            0x00000020, // reclaimable
  2546. "$recatter":                0x00000040,
  2547. "$limitedlinks":            0x00000080,
  2548. "$newsclicktracking":       0x00000100,
  2549. "$titleclicktracking":      0x00000200,
  2550. "$unlimitedslpromptclicks": 0x00000400,
  2551. "$adultrrecat":             0x00000800,
  2552. "$adultxrecat":             0x00001000,
  2553. "$has_subscriptions":        0x00002000};
  2554.  
  2555. // _TABLE_IDS_BY_NAME dictionary
  2556. const su_const_tables = {
  2557. "contact":"c",
  2558. "dyn_channel":"d",
  2559. "slclick":"s",
  2560. "stumble_visited_urls":"v"};
  2561.  
  2562. // The amount of time to wait between submission of failed stumble reports
  2563. const su_const_stumble_report_timeouts_s = {
  2564.     0: 0,
  2565.     1: 60,
  2566.     2: 120,
  2567.     3: 180,
  2568.     4: 360,
  2569.     5: 720,
  2570.     6: 1440,
  2571.     7: 2880,
  2572.     8: 5000,
  2573.     9: 10000,
  2574.     10: 20000,
  2575.     11: 40000,
  2576.     12: 86400,
  2577.     "last": 86400
  2578. };
  2579.  
  2580. // _DEFAULTS_BY_ID dictionary
  2581. const su_const_defaults = {
  2582.  
  2583. // browser session global variable defaults
  2584. "~batched_error_log":          "",    // overridden
  2585. "~batched_pref_error_log":     "",    // overridden
  2586. "~discovery_count":            0,
  2587. "~download_favs_context":      null,
  2588. "~password_app_salt":          "StumbleUpon public salt",
  2589. "~password_store_key":         "http://www.stumbleupon.com/toolbar-auth/",
  2590. "~message_count":              0,
  2591. "~shown_thru_domain_info_count_max": 5,
  2592. "~shown_prompt2":              false,
  2593. "~visited_find_friends":       false,
  2594. "~visited_signup":             false,
  2595.  
  2596. // user session global variable defaults
  2597. "#checked_dyn_channels":       false,
  2598. "#checked_facebook":           false,
  2599. "#checking_facebook":          false,
  2600. "#command_queue_context":      null,
  2601. "#download_favs_detail":       null,
  2602. "#facebook_userid":            0,
  2603. "#find_friends_facebook_count": 0,
  2604. "#find_friends_optin":         false,
  2605. "#find_friends_pre":           "",
  2606. "#installing_all_avatars":     false,
  2607. "#installing_favicons":        false,
  2608. "#migrating_places":           false,
  2609. "#prev_friends":               "",
  2610. "#prev_nick":                  "",
  2611. "#prev_topic_list":            "",
  2612. "#recent_info_spec":           {},
  2613. "#sldetail":                   null,
  2614. "#slprocessed":                false,
  2615.  
  2616. // client preference defaults
  2617. "@auto_cookie_exceptions":        true,
  2618. "@category_reset_timeout":     1 * 60 * 60 * 1000,
  2619. "@clear_favicons":             false,
  2620. "@click_throttle_ms":          1500,
  2621. "@client_form":                0,
  2622. "@client_migration_state":     0,     // overridden
  2623. "@client_version":             "",    // overridden
  2624. "@current_user":               "",
  2625. "@db_visitedurls_fail":        false,
  2626. "@dd_display_message":         false,
  2627. "@dd_links_m":                 "",
  2628. "@dd_uc":                      false,
  2629. "@dd_uc_server":               "",
  2630. "@dist_id_list":               "",
  2631. "@dist_reg":                   "0",   // read via getIntValue()
  2632. "@dist_regid":                 "",
  2633. "@enable_db_backup":           false,
  2634. "@enable_prompt1":             true,
  2635. "@enable_prompt2":             true,
  2636. "@enable_refer":               true,
  2637. "@enable_secure_store_auth":   false,
  2638. "@enable_server_counts":        true,
  2639. "@enable_slstats":             true,
  2640. "@enable_userfile_failsafe":   true,
  2641. "@enable_visitedurls_failsafe":true,
  2642. "@favicon_update_time_spec":   {},
  2643. "@facebook_client_invite_count": 0,
  2644. "@facebook_user":              false,
  2645. "@fbcontacts":                 {},    // stored in prefs table
  2646. "@first_run_time":                "0",  // First time seen in seconds (read via getIntValue())
  2647. "@first_version":                "",
  2648. "@id_list":                    "",
  2649. "@installed":                  "0",   // read via getIntValue()
  2650. "@json_db":                    {},    // obsolete v3.05
  2651. "@latch-to-sidebar":           false,
  2652. "@log_prefetch_progress":      false,
  2653. "@min_noscript_for_prefetch":  "1.9.8.4",
  2654. "@position-group":             "first",
  2655. "@position_history":           "stumbleupon",
  2656. "@recommend_timeout_ms":       60000,
  2657. "@report_error_count":         0,
  2658. "@report_error_count_max":     3,     // overridden
  2659. "@right-justify-width":        0,     // overridden
  2660. "@search-width":               156,
  2661. "@server_time_float_s":        3,
  2662. "@shown_toolbar":              false,
  2663. "@stumble_action_timeout_ms":  15000,
  2664. "@stumble_max_visited_urls":   50,
  2665. "@stumble_report_interval_ms": 60000,
  2666. "@stumble_report_throttle_ms": 60000,
  2667. "@stumble_submission_timeout_ms": 60000,
  2668. "@supr_domain":                    "su.pr",
  2669. "@time_spec":                  {client:0,server:0}, // obsolete v3.08
  2670. "@toolbar-position":           "stumbleupon",
  2671. "@toolbar_toggle_visible":     false,
  2672. "@toolbar-visible":            true,
  2673. "@update_avatar_on_receive":   true,  // obsolete v3.08
  2674. "@update_avatar_on_send":      true,  // obsolete v3.08
  2675. "@userfile_write_failed":      false,
  2676. "@whitelist_upon_load":        false,
  2677.  
  2678. // user preference defaults
  2679. "$activity_time_s":            "0",   // read via getIntValue()
  2680. "$autocomplete_type":          "tag,query",
  2681. "$autologout":                 false,
  2682. "$bad_stumble":                false,
  2683. "$block_flash_popups":         true,
  2684. "$bm_folderid":                0,
  2685. "$bm_sufav_itemid":            0,
  2686. "$bm_suvid_itemid":            0,
  2687. "$check-referral":             "",    // obsolete v3.21
  2688. "$comment_firstrating":        true,
  2689. "$contacts":                   {},    // stored in prefs table
  2690. "$dd_bad_types":               false,
  2691. "$dd_rec_label":               "[rec label]",
  2692. "$dd_rec_rating":              false,
  2693. "$default_thru_domain_list":   "",
  2694. "$download_favs_state":        "a",
  2695. "$download_favs_detail":       {},
  2696. "$dyn_channels":               {},    // stored in prefs table
  2697. "$emails":                     "",    // obsolete v3.0
  2698. "$facebook_added":             false,
  2699. "$facebook_contacts_time_s":   0,
  2700. "$facebook_homeprompt_time_s": 0,
  2701. "$facebook_homeprompt_optout": false,
  2702. "$facebook_invite_count":      0,
  2703. "$facebook_linked":            false,
  2704. "$facebook_supr_linked":       false,
  2705. "$firstfriends":               "",    // unused by client
  2706. "$form":                       1,
  2707. "$friends":                    "FRIEND", // obsolete v3.0
  2708. "$friends_synced":             "0",   // read via getIntValue()
  2709. "$great_stumble":              false,
  2710. "$has_avatars":                false,
  2711. "$has_downloaded_favs":        false, // obsolete v3.27
  2712. "$has_favicons":               false,
  2713. "$icons":                      "text-icons",
  2714. "$interests":                  "",
  2715. "$imported_fbcontacts_time_s": 0,
  2716. "$imported_contacts_time_s":   0,
  2717. "$info_time_s":                "0",   // read via getIntValue()
  2718. "$intro_count":                0,
  2719. "$last_incat":                 "0",
  2720. "$last_stumble":               "0",   // read via getIntValue()
  2721. "$last_uploaded":              "0",   // read via getIntValue()
  2722. "$migrate_places_state":       "d",
  2723. "$migrate_places_key":         "",
  2724. "$migrate_places_idx":         0,
  2725. "$migration_state":            0,     // overridden
  2726. "$newmessage":                 false,
  2727. "$nick":                       "",
  2728. "$password":                   "",    // obsolete v3.0
  2729. "$poll_time_s":                "0",   // read via getIntValue()
  2730. "$poll_state":                 "a",
  2731. "$prefetch":                   true,
  2732. "$prefetcher_fetch_depth_in_query": -1,
  2733. "$prefetcher_fetch_depth_in_topic": 3,
  2734. "$prefetcher_pass_1_timeout_ms": 10000,
  2735. "$prefetcher_pass_2_timeout_ms": 30000,
  2736. "$prefetcher_pass_3_timeout_ms": 120000,
  2737. "$prefetcher_pass_max":        3,
  2738. "$prefetcher_skip_resources":  false,
  2739. "$process_rarely_timestamp":   "0",   // read via getIntValue()
  2740. "$query_history_depth":        100,
  2741. "$rate_new_window":            false,
  2742. "$recat_adult":                0,
  2743. "$recent_sendtos_menu_depth":  15,
  2744. "$recently_seen":              "",
  2745. "$recently_seen_publicids":    "",
  2746. "$recently_seen_referralids":  "",
  2747. "$referral_count":             "0",   // obsolete v3.21
  2748. "$referral_throbber_interval_ms": 5000,
  2749. "$review_new_window":          false,
  2750. "$search_clear_queries":       false,
  2751. "$search_new_window":          false,
  2752. "$searchlink_logos":           true,  // obsolete v3.08
  2753. "$sender_click_platform":      false,
  2754. "$sendtos":                    "",    // obsolete v2.7
  2755. "$sendtos_menu_depth":         16,
  2756. "$sendto_stats":               "",    // obsolete v3.0
  2757. "$shortcut_reviews":           "",    // platform-specific
  2758. "$shortcut_stumble":           "",    // platform-specific
  2759. "$shortcut_tag":               "",    // Alt+VK_SLASH
  2760. "$shortcut_thumbdown":         "",    // platform-specific
  2761. "$shortcut_thumbup":           "",    // platform-specific
  2762. "$shortcut_toolbar":           "",    // platform-specific
  2763. "$shortcut-reviews":           "",    // obsolete v2.7
  2764. "$shortcut-stumble":           "",    // obsolete v2.7
  2765. "$shortcut-thumbdown":         "",    // obsolete v2.7
  2766. "$shortcut-thumbup":           "",    // obsolete v2.7
  2767. "$shortcut-toolbar":           "",    // obsolete v2.7
  2768. "$shortcuts_enabled":          false,
  2769. "$show_aboutme":               false,
  2770. "$show_editinfo":              false, // obsolete v3.0
  2771. "$show_field":                 false,
  2772. "$show_filter":                false,
  2773. "$show_firstrater_label_always": false,
  2774. "$show_flag":                  false, // obsolete v3.27
  2775. "$show_forums":                false, // obsolete v3.07
  2776. "$show_friends":               false,
  2777. "$show_friends_user_changed":  false,
  2778. "$show_groups":                false,
  2779. "$show_home":                  false,
  2780. "$show_home_user_changed":     false,
  2781. "$show_info":                  false,
  2782. "$show_info_user_changed":     false,
  2783. "$show_legacy_forums":         false, // obsolete v3.63
  2784. "$show_legacy_network":        false, // obsolete v3.38?
  2785. "$show_matches":               false,
  2786. "$show_messages":              false,
  2787. "$show_mode":                  false,
  2788. "$show_mode_all":              true,
  2789. "$show_mode_friends":          true,
  2790. "$show_mode_more":             true,
  2791. "$show_mode_news":             true,
  2792. "$show_mode_photo":            true,
  2793. "$show_mode_search":           false,
  2794. "$show_mode_stumbler":         true,
  2795. "$show_mode_stumblers":        false,
  2796. "$show_mode_video":            true,
  2797. "$show_mode_wiki":             false,
  2798. "$show_myinfo":                false, // undocumented feature
  2799. "$show_mystumblers":           false, // obsolete v3.07
  2800. "$show_referral":              true,
  2801. "$show_referral_user_changed": false,
  2802. "$show_search":                false, // obsolete v3.0
  2803. "$show_searchlinks":           false, // obsolete v3.08
  2804. "$show_searchlinks_comment_icon": false,
  2805. "$show_searchlinks_friends":   false,
  2806. "$show_searchlinks_logo":      true,
  2807. "$show_searchlinks_tooltip":   true,  // undocumented feature
  2808. "$show_searchlinks_topic":     false,
  2809. "$show_searchlinks_score":     false,
  2810. "$show_separators":            true,
  2811. "$show_tag":                   false,
  2812. "$show_topics":                true,
  2813. "$show_tutorial_info":         false,
  2814. "$shown_find_friends":         false,
  2815. "$shown_find_friends_clicks":  0,
  2816. "$shown_find_friends_time_s":  0,
  2817. "$shown_find_friends_optout":  false,
  2818. "$shown_photo_info":           false,
  2819. "$shown_position_dialog":        false,
  2820. "$shown_rate_info":            false, //!!!
  2821. "$shown_referral_info":        false,
  2822. "$shown_reviews_info":         false,
  2823. "$shown_searchlinks_dialog":   false,
  2824. "$shown_searchlinks":          false,
  2825. "$shown_thru_domain_info_count": 0,
  2826. "$shown_thru_domain_info_list": "",
  2827. "$shown_toall_info":           false,
  2828. "$shown_tomore_info":          false,
  2829. "$shown_tag":                  false,
  2830. "$slclicks":                   {},    // stored in prefs table
  2831. "$slidfstats":                 "0:0:0:0:0:0:0:0:0:0",
  2832. "$slistats":                   "0:0:0:0:0:0:0:0:0:0",
  2833. "$slstats":                    "",
  2834. "$sponsor":                    false, // unused by client
  2835. "$stumble_count":              0,
  2836. "$stumble_last_report":        "0", // Read via getIntValue
  2837. "$stumble_report_started":     "0", // Read via getIntValue
  2838. "$stumble_report_retrycount":  0, // The stumble report retransmission state.  0 = No failures yet.  1 = Failed once, 2 = failed twice, ...
  2839. "$stumble_report_lastfail":    0,
  2840. "$stumble_topics":             false,
  2841. "$stumble_topics_style":       1, // 1 = [default] recat menu, located at right ; 0 = recat menu, located at left ; 2 = legacy behavior (reviews page button located at right)
  2842. "$stumble_upon_change":        true,
  2843. "$stumblereferrals":           "",
  2844. "$stumblestats":               "",
  2845. "$stumbletimes":               "",
  2846. "$stumbletypes":               "",
  2847. "$sync_bm_adult":              false,
  2848. "$sync_bm_meta":               true,
  2849. "$sync_bm_delete_autotags":    true,
  2850. "$sync_cur_q":                 0,
  2851. "$sync_cur_t":                 "",
  2852. "$sync_cur_s":                 "",
  2853. "$sync_pre_q":                 0,
  2854. "$sync_pre_t":                 "",
  2855. "$sync_pre_s":                 "",
  2856. "$sync_retry":                 0,
  2857. "$sync_retry_time_s":          "0",   // read via getIntValue()
  2858. "$sync_time_s":                0,
  2859. "$tag_history_depth":          100,
  2860. "$tagged_discovery_count":     0,
  2861. "$thumbdown_count":            0,
  2862. "$thumbup_count":              0,
  2863. "$twitter_supr_linked":        false,
  2864. "$token":                      "",
  2865. "$undelivered_count":          0,
  2866. "$version":                    "",    // overridden
  2867. "$ycc":                        ""};
  2868.  
  2869.